Compare commits

...

78 Commits
1.0.0 ... 1.3.0

Author SHA1 Message Date
Rowan Manning
ff239edf5a Version 1.3.0 2014-03-04 14:28:03 +00:00
Rowan Manning
c2013e42d4 Commit style changes 2014-03-04 14:15:31 +00:00
Rowan Manning
a79a5a2fe6 Merge branch 'filter-urls' of github.com:nature/pa11y-dashboard into develop 2014-03-04 14:14:49 +00:00
perryharlock
85fe2c4a37 Move toggle functionality from filter input to containing div 2014-03-04 14:08:57 +00:00
Rowan Manning
c04396e80e Merge branch 'gpl-preamble' of github.com:nature/pa11y-dashboard into develop 2014-02-10 14:56:06 +00:00
Jude Robinson
7b10f2de91 adding the gpl preamble 2014-02-10 14:08:38 +00:00
perryharlock
890ec38216 Add filter styling 2014-01-21 10:50:57 +00:00
Rowan Manning
d8cb1b6c71 Write the JavaScript for URL filtering 2014-01-14 11:40:23 +00:00
Rowan Manning
a605835cc9 Attempt to fix timeout errors in tests 2014-01-13 09:59:21 +00:00
perryharlock
01897d8a17 Amend styles for ignore button 2014-01-13 09:59:21 +00:00
Rowan Manning
02e22eb094 Add "unigore" buttons to ignored rules 2014-01-13 09:59:13 +00:00
perryharlock
dfac541294 Amends to task-card min heights 2014-01-13 09:59:13 +00:00
Rowan Manning
f3b295982f Fix typo 2014-01-13 09:58:35 +00:00
Rowan Manning
ddf2c705c9 Fix the ignore buttons for readonly/result pages 2014-01-13 09:58:35 +00:00
perryharlock
20de93bf2d Change ignore rules in results to come from mainResult 2014-01-13 09:58:35 +00:00
Rowan Manning
ccc7ddfc18 Write the back-end for rule ignoring 2014-01-13 09:58:35 +00:00
perryharlock
4347acf654 Issue 65 - Ability to select a rule to ignore from result - css / html 2014-01-13 09:58:35 +00:00
Rowan Manning
da9b383909 Fix mistakes in versioning instructions 2014-01-13 09:58:34 +00:00
Rowan Manning
d0feee8dd5 Version 1.2.3 2014-01-13 09:38:10 +00:00
Rowan Manning
f97e224679 Update the tests to allow for the new CSV format 2014-01-13 09:37:16 +00:00
Rowan Manning
ddbb0db33d Remove spaces in the CSV header row 2014-01-13 09:33:51 +00:00
Quannon Au
e0290b4fc5 Issue 74 - Fix CSV format for Mac Excel 2014-01-10 11:25:16 -08:00
perryharlock
1f6ea332ac Version 1.2.2 2014-01-09 11:44:25 +00:00
perryharlock
5b109fb23d Amend versioning instructions 2014-01-09 11:43:44 +00:00
perryharlock
3b03af7e8f Merge branch 'develop' of github.com:nature/pa11y-dashboard into develop 2014-01-09 11:05:22 +00:00
perryharlock
1c96369bb0 Issue 68 - Bad spacing when graph not visible 2014-01-09 11:04:53 +00:00
Rowan Manning
e421444487 Versioning clarifications 2014-01-09 10:36:08 +00:00
Rowan Manning
5c7d9bfc43 Add notes on publishing a release 2014-01-09 10:31:50 +00:00
Rowan Manning
75497ff95f Version 1.2.1 2014-01-08 11:51:57 +00:00
perryharlock
c481f8dbb5 IE7 and IE8 amends for Options dropdown positioning
Conflicts:
	public/css/site.min.css
2014-01-08 11:43:47 +00:00
perryharlock
716151e696 Include IE8and.less file and make IE amends for Options dropdowns
Conflicts:
	public/css/site.min.css
2014-01-08 11:42:34 +00:00
Rowan Manning
b1de71f59c Version 1.2.0 2013-12-12 14:39:19 +00:00
Rowan Manning
4e19b125e0 Add a count for ignored rules 2013-12-12 14:36:14 +00:00
perryharlock
d3148d4194 Add HTML Codesniffer links 2013-12-12 14:17:54 +00:00
Rowan Manning
1ad95627ee Don't trim trailing spaces in markdown 2013-12-12 09:38:21 +00:00
Rowan Manning
4296effbc1 Refactor to reduce repetition 2013-12-11 14:12:25 +00:00
Rowan Manning
917057a109 Display the ignore rules for results, not tasks 2013-12-11 14:06:51 +00:00
Rowan Manning
c8b97df4ee Merge branch 'edit-page' of github.com:nature/pa11y-dashboard into develop 2013-12-02 15:32:40 +00:00
perryharlock
724175ef66 Add number of ignore rules to result page 2013-12-02 11:58:01 +00:00
perryharlock
b2273234ce Merge branch 'edit-page' of github.com:nature/pa11y-dashboard into edit-page 2013-11-29 15:14:31 +00:00
perryharlock
0546175809 Change link decriptions for editing and delting a task 2013-11-29 15:14:22 +00:00
Rowan Manning
52a923ace3 Write basic tests for task editing 2013-11-28 13:59:27 +00:00
Rowan Manning
786922e592 Add an .editorconfig file 2013-11-28 13:28:28 +00:00
Rowan Manning
4ff53093f4 Link breadcrumb on task sub-pages 2013-11-28 08:59:05 +00:00
Rowan Manning
ce77e57659 Fix an issue with saving empty ignore rules 2013-11-28 08:54:40 +00:00
Rowan Manning
4a7800e288 Wire up task editing 2013-11-27 16:47:14 +00:00
Rowan Manning
5b1963599b Update pa11y-webservice to include edit endpoint 2013-11-27 16:38:19 +00:00
perryharlock
1b36dc12ea make dropdowns appear on hover for non js users 2013-11-27 16:37:52 +00:00
perryharlock
963ab33cce Make edit route work and add options dropdown 2013-11-27 16:21:18 +00:00
perryharlock
b95238645a Merge branch 'develop' of github.com:nature/pa11y-dashboard into edit-page 2013-11-27 14:11:45 +00:00
perryharlock
8657138e13 Fix linting erros 2013-11-27 13:58:55 +00:00
perryharlock
f580f00d4c Reduce font size for tooltips in graph 2013-11-27 13:40:27 +00:00
perryharlock
fdc631e3ca Merge branch 'develop' of github.com:nature/pa11y-dashboard into develop 2013-11-27 13:38:06 +00:00
perryharlock
98dafba137 Small tweak to tooltip appearance on graph 2013-11-27 13:37:42 +00:00
Rowan Manning
fd32a5d894 Cache-bust the CSS and JS 2013-11-27 13:29:19 +00:00
perryharlock
68a3e26472 Disable fields that are not editable 2013-11-27 11:40:22 +00:00
Rowan Manning
bb197744fd Add dates to graph tooltips 2013-11-27 11:31:42 +00:00
perryharlock
ae6b551f54 Merge branch 'develop' of github.com:nature/pa11y-dashboard into edit-page 2013-11-27 11:30:59 +00:00
perryharlock
16231a3609 Amend x-axis label width 2013-11-27 11:27:31 +00:00
perryharlock
74dd5b18c9 Add route and view for edit page 2013-11-27 11:13:19 +00:00
perryharlock
5c10261c56 Fix x-axis - stop multiple appearances of dates 2013-11-26 11:36:25 +00:00
perryharlock
e13de45e4a Fix lint error 2013-11-25 16:37:50 +00:00
perryharlock
9383de3410 Amend xaxis mode to time from category to try to reduce x axis clutter 2013-11-25 16:19:01 +00:00
perryharlock
7c2647653d issue 57 - make y axis display ticks as integers 2013-11-25 11:27:36 +00:00
Rowan Manning
2ebb54f545 Version 1.1.0 2013-11-22 14:01:53 +00:00
Rowan Manning
d57ae45b4f Write tests for result pages (and related actions) 2013-11-22 11:44:54 +00:00
Rowan Manning
ea330548b1 Write tests for task pages (and related actions) 2013-11-22 11:10:57 +00:00
Rowan Manning
ae5b214834 Write tests for the new URL form 2013-11-22 09:17:44 +00:00
Rowan Manning
b5735b7f05 Reload fixtures for tests and finish testing home 2013-11-21 13:54:52 +00:00
Rowan Manning
a47fb38d7f Add test running instructions to the readme 2013-11-21 12:04:42 +00:00
Rowan Manning
da0e98eab1 Update the Travis config to run tests 2013-11-21 11:52:40 +00:00
Rowan Manning
623a52e112 Build a basic framework for functional testing 2013-11-21 09:58:44 +00:00
Rowan Manning
9d72e50b4e Update docs to include webservice dependencies 2013-11-21 09:25:28 +00:00
Rowan Manning
3535b9b11c Document new configuration options 2013-11-21 09:21:15 +00:00
Rowan Manning
8f636173a0 Allow the webservice to run automatically 2013-11-21 09:12:54 +00:00
Rowan Manning
ec9f82aa6f Add build status to readme 2013-11-20 13:47:47 +00:00
Rowan Manning
34a7c351c9 Add Travis config 2013-11-20 13:46:47 +00:00
Rowan Manning
c13af05422 Fix lint errors 2013-11-20 13:46:41 +00:00
68 changed files with 2468 additions and 281 deletions

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
# Config files # Config files
config/development.json config/development.json
config/production.json config/production.json
config/test.json
# Generated npm files # Generated npm files
node_modules node_modules

24
.travis.yml Normal file
View File

@@ -0,0 +1,24 @@
# Language/versions
language: node_js
node_js:
- "0.10"
# Services setup
services:
- mongodb
# Build script
before_script:
- npm install -g grunt-cli
- cp config/test.sample.json config/test.json
- grunt start-test &
- sleep 5 # give server time to start
script: 'grunt ci'
# Notifications
notifications:
email:
- j.robinson@nature.com
- perry.harlock@nature.com
- rowan.manning@nature.com

View File

@@ -31,8 +31,23 @@ Coding Guidelines
* Don't commit code without passing tests (run `grunt test`). * Don't commit code without passing tests (run `grunt test`).
Versioning
----------
We use [Semantic Versioning][semver] in this project. The process for releasing a new version is as follows; this should only be done by core contributors you don't need to include a tagged version in your pull-requests.
* Switch to `master` and merge the `develop` branch into it
* Update the version number in `package.json` and `README.md`
* Commit the changes with the message: "Version x.x.x" (x.x.x being the new version number)
* Tag the commit with the version number (just the numbers, no "version" or "v"): `git tag x.x.x`
* Push with tags: `git push && git push --tags`
* Check out the `develop` branch, merge `master` into it, and push
* On GitHub, add [release notes][release-notes] for the new version. The title should be "Version x.x.x", and the description should be a list of new features/fixes
[bugs]: https://github.com/nature/pa11y-dashboard/issues?labels=bug&state=open [bugs]: https://github.com/nature/pa11y-dashboard/issues?labels=bug&state=open
[ready]: https://github.com/nature/pa11y-dashboard/issues?labels=ready&state=open [ready]: https://github.com/nature/pa11y-dashboard/issues?labels=ready&state=open
[issues]: https://github.com/nature/pa11y-dashboard/issues [issues]: https://github.com/nature/pa11y-dashboard/issues
[milestones]: https://github.com/nature/pa11y-dashboard/issues/milestones [milestones]: https://github.com/nature/pa11y-dashboard/issues/milestones
[release-notes]: https://github.com/nature/pa11y-dashboard/releases
[semver]: http://semver.org/

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
module.exports = function (grunt) { module.exports = function (grunt) {
grunt.initConfig({ grunt.initConfig({
@@ -34,6 +49,16 @@ module.exports = function (grunt) {
} }
}, },
mochaTest: {
functional: {
src: ['test/functional/**/*.js'],
options: {
reporter: 'spec',
timeout: 4000
}
}
},
nodemon: { nodemon: {
development: { development: {
options: { options: {
@@ -43,6 +68,15 @@ module.exports = function (grunt) {
NODE_ENV: 'development' NODE_ENV: 'development'
} }
} }
},
test: {
options: {
cwd: __dirname,
file: 'index.js',
env: {
NODE_ENV: 'test'
}
}
} }
}, },
@@ -57,8 +91,10 @@ module.exports = function (grunt) {
'public/js/vendor/bootstrap/js/alert.js', 'public/js/vendor/bootstrap/js/alert.js',
'public/js/vendor/bootstrap/js/dropdown.js', 'public/js/vendor/bootstrap/js/dropdown.js',
'public/js/vendor/bootstrap/js/tooltip.js', 'public/js/vendor/bootstrap/js/tooltip.js',
'public/js/vendor/bootstrap/js/transition.js',
'public/js/vendor/bootstrap/js/collapse.js',
'public/js/vendor/flot/jquery.flot.js', 'public/js/vendor/flot/jquery.flot.js',
'public/js/vendor/flot/jquery.flot.categories.js', 'public/js/vendor/flot/jquery.flot.time.js',
'public/js/vendor/flot/jquery.flot.selection.js', 'public/js/vendor/flot/jquery.flot.selection.js',
'public/js/vendor/flot/jquery.flot.resize.js', 'public/js/vendor/flot/jquery.flot.resize.js',
'public/js/site.js' 'public/js/site.js'
@@ -84,12 +120,15 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-nodemon'); grunt.loadNpmTasks('grunt-nodemon');
grunt.registerTask('lint', ['jshint']); grunt.registerTask('lint', ['jshint']);
grunt.registerTask('test', ['mochaTest']);
grunt.registerTask('compile', ['less', 'uglify']); grunt.registerTask('compile', ['less', 'uglify']);
grunt.registerTask('start', ['nodemon:development']); grunt.registerTask('start', ['nodemon:development']);
grunt.registerTask('default', ['compile', 'lint']); grunt.registerTask('start-test', ['nodemon:test']);
grunt.registerTask('ci', ['compile', 'lint']); grunt.registerTask('default', ['compile', 'lint', 'test']);
grunt.registerTask('ci', ['lint', 'test']);
}; };

View File

@@ -3,7 +3,8 @@ pa11y-dashboard
pa11y-dashboard is a web interface to the [pa11y][pa11y] accessibility reporter; allowing you to focus on *fixing* issues rather than hunting them down. pa11y-dashboard is a web interface to the [pa11y][pa11y] accessibility reporter; allowing you to focus on *fixing* issues rather than hunting them down.
**Current Version:** *1.0.0* **Current Version:** *1.3.0*
**Build Status:** [![Build Status][travis-img]][travis]
**Node Version Support:** *0.10* **Node Version Support:** *0.10*
@@ -14,7 +15,7 @@ pa11y-dashboard is a web interface to the [pa11y][pa11y] accessibility reporter;
Setup Setup
----- -----
pa11y-dashboard requires [Node.js][node] 0.10+ and [pa11y-webservice][pa11y-webservice] to be installed and running. You'll need to follow the setup guide for pa11y-webservice before setting up pa11y-dashboard. pa11y-dashboard requires [Node.js][node] 0.10+, [PhantomJS][phantom], and [MongoDB][mongo] to be installed. See the [pa11y][pa11y] and [pa11y-webservice][pa11y-webservice] documentation for more information on these dependencies.
You'll then need to clone this repo locally and install dependencies with `npm install`. You'll then need to clone this repo locally and install dependencies with `npm install`.
@@ -23,6 +24,7 @@ Once you have a local clone, you'll need to copy some sample configuration files
```sh ```sh
$ cp config/development.sample.json config/development.json $ cp config/development.sample.json config/development.json
$ cp config/production.sample.json config/production.json $ cp config/production.sample.json config/production.json
$ cp config/test.sample.json config/test.json
``` ```
Each of these files defines configurations for a different environment. If you're just running the application locally, then you should be OK with just development configurations. The [available configurations are documented here](#configurations). Each of these files defines configurations for a different environment. If you're just running the application locally, then you should be OK with just development configurations. The [available configurations are documented here](#configurations).
@@ -32,6 +34,7 @@ Now that you've got your application configured, you can run in each mode with t
```sh ```sh
$ NODE_ENV=production node . # Run in production $ NODE_ENV=production node . # Run in production
$ NODE_ENV=development node . # Run in development $ NODE_ENV=development node . # Run in development
$ NODE_ENV=test node . # Run in test
``` ```
Check the [development instructions](#development) for more information about running locally (and restarting automatically when files change). Check the [development instructions](#development) for more information about running locally (and restarting automatically when files change).
@@ -42,9 +45,6 @@ Configurations
The boot configurations for pa11y-dashboard are as follows. Look at the sample JSON files in the repo for example usage. The boot configurations for pa11y-dashboard are as follows. Look at the sample JSON files in the repo for example usage.
### webservice
*(string)* The base URL of the [pa11y-webservice][pa11y-webservice] instance you intend on using.
### port ### port
*(number)* The port to run the application on. *(number)* The port to run the application on.
@@ -57,12 +57,21 @@ The boot configurations for pa11y-dashboard are as follows. Look at the sample J
### siteMessage ### siteMessage
*(string)* A message to display prominently on the site home page. Defaults to `null`. *(string)* A message to display prominently on the site home page. Defaults to `null`.
### webservice
This can either be an object containing [pa11y-webservice configurations][pa11y-webservice-config], or a string which is the base URL of a [pa11y-webservice][pa11y-webservice] instance you are running separately.
Development Development
----------- -----------
To develop pa11y-dashboard, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). You'll also need [Grunt][grunt] to be installed globally in order to run tests, you can do this with `npm install -g grunt-cli`. To develop pa11y-dashboard, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). You'll also need [Grunt][grunt] to be installed globally in order to run tests, you can do this with `npm install -g grunt-cli`.
Once you've done this, you'll need to start the application in test mode with:
```sh
$ grunt start-test
```
Now you'll be able to run the following commands: Now you'll be able to run the following commands:
```sh ```sh
@@ -70,6 +79,8 @@ $ grunt # Run the lint and test tasks together
$ grunt lint # Run JSHint with the correct config $ grunt lint # Run JSHint with the correct config
$ grunt compile # Compile front-end assets $ grunt compile # Compile front-end assets
$ grunt start # Run app in development mode, restarting if files change $ grunt start # Run app in development mode, restarting if files change
$ grunt start-test # Run app in test mode, restarting if files change
$ grunt test # Run functional tests
$ grunt watch # Watch for file changes and compile assets $ grunt watch # Watch for file changes and compile assets
``` ```
@@ -88,7 +99,11 @@ pa11y-dashboard is licensed under the [GNU General Public License 3.0][gpl].
[gpl]: http://www.gnu.org/licenses/gpl-3.0.html [gpl]: http://www.gnu.org/licenses/gpl-3.0.html
[grunt]: http://gruntjs.com/ [grunt]: http://gruntjs.com/
[mongo]: http://www.mongodb.org/
[node]: http://nodejs.org/ [node]: http://nodejs.org/
[pa11y]: https://github.com/nature/pa11y [pa11y]: https://github.com/nature/pa11y
[pa11y-webservice]: https://github.com/nature/pa11y-webservice [pa11y-webservice]: https://github.com/nature/pa11y-webservice
[supervisor]: https://github.com/isaacs/node-supervisor [pa11y-webservice-config]: https://github.com/nature/pa11y-webservice#configurations
[phantom]: http://phantomjs.org/
[travis]: https://travis-ci.org/nature/pa11y-dashboard
[travis-img]: https://travis-ci.org/nature/pa11y-dashboard.png?branch=master

26
app.js
View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var createClient = require('pa11y-webservice-client-node'); var createClient = require('pa11y-webservice-client-node');
@@ -13,11 +28,16 @@ module.exports = initApp;
function initApp (config, callback) { function initApp (config, callback) {
config = defaultConfig(config); config = defaultConfig(config);
var webserviceUrl = config.webservice;
if (typeof webserviceUrl == 'object') {
webserviceUrl = 'http://' + webserviceUrl.host + ':' + webserviceUrl.port + '/';
}
var app = new EventEmitter(); var app = new EventEmitter();
app.address = null; app.address = null;
app.express = express(); app.express = express();
app.server = http.createServer(app.express); app.server = http.createServer(app.express);
app.webservice = createClient(config.webservice); app.webservice = createClient(webserviceUrl);
// Compression // Compression
app.express.use(express.compress()); app.express.use(express.compress());
@@ -44,6 +64,7 @@ function initApp (config, callback) {
// View helpers // View helpers
require('./view/helper/date')(hbs.registerHelper); require('./view/helper/date')(hbs.registerHelper);
require('./view/helper/string')(hbs.registerHelper);
require('./view/helper/url')(hbs.registerHelper); require('./view/helper/url')(hbs.registerHelper);
// Populate view locals // Populate view locals
@@ -73,6 +94,9 @@ function initApp (config, callback) {
require('./route/new')(app); require('./route/new')(app);
require('./route/task/delete')(app); require('./route/task/delete')(app);
require('./route/task/run')(app); require('./route/task/run')(app);
require('./route/task/edit')(app);
require('./route/task/ignore')(app);
require('./route/task/unignore')(app);
} }
// Error handling // Error handling

View File

@@ -1,6 +1,12 @@
{ {
"webservice": "http://localhost:3000/",
"port": 4000, "port": 4000,
"noindex": true, "noindex": true,
"readonly": false "readonly": false,
"webservice": {
"database": "mongodb://localhost/pa11y-webservice-dev",
"host": "0.0.0.0",
"port": 3000,
"cron": "0 30 0 * * *"
}
} }

View File

@@ -1,6 +1,12 @@
{ {
"webservice": "http://localhost:3000/",
"port": 4000, "port": 4000,
"noindex": true, "noindex": true,
"readonly": false "readonly": false,
"webservice": {
"database": "mongodb://localhost/pa11y-webservice",
"host": "0.0.0.0",
"port": 3000,
"cron": "0 30 0 * * *"
}
} }

12
config/test.sample.json Normal file
View File

@@ -0,0 +1,12 @@
{
"port": 4000,
"noindex": true,
"readonly": false,
"webservice": {
"database": "mongodb://localhost/pa11y-webservice-test",
"host": "0.0.0.0",
"port": 3000,
"cron": "0 30 0 * * *"
}
}

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* jshint maxlen: false */ /* jshint maxlen: false */
'use strict'; 'use strict';

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var chalk = require('chalk'); var chalk = require('chalk');
@@ -18,4 +33,14 @@ require('./app')(config, function (err, app) {
console.error(chalk.grey(stack.join('\n'))); console.error(chalk.grey(stack.join('\n')));
}); });
// Start the webservice if required
if (typeof config.webservice === 'object') {
require('pa11y-webservice')(config.webservice, function (err, webservice) {
console.log('');
console.log(chalk.underline.cyan('pa11y-webservice started'));
console.log(chalk.grey('mode: %s'), process.env.NODE_ENV);
console.log(chalk.grey('uri: %s'), webservice.server.info.uri);
});
}
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "pa11y-dashboard", "name": "pa11y-dashboard",
"version": "1.0.0", "version": "1.3.0",
"private": true, "private": true,
"description": "pa11y-dashboard is a visual web interface to the pa11y accessibility reporter", "description": "pa11y-dashboard is a visual web interface to the pa11y accessibility reporter",
@@ -25,7 +25,8 @@
"express": "~3.4", "express": "~3.4",
"express-hbs": "~0.2", "express-hbs": "~0.2",
"moment": "~2.2", "moment": "~2.2",
"pa11y-webservice-client-node": "~1.0", "pa11y-webservice": "~1.3",
"pa11y-webservice-client-node": "~1.1",
"underscore": "~1.5" "underscore": "~1.5"
}, },
"devDependencies": { "devDependencies": {
@@ -35,7 +36,11 @@
"grunt-contrib-less": "~0.8", "grunt-contrib-less": "~0.8",
"grunt-contrib-uglify": "~0.2", "grunt-contrib-uglify": "~0.2",
"grunt-contrib-watch": "~0.5", "grunt-contrib-watch": "~0.5",
"grunt-nodemon": "~0.1" "grunt-mocha-test": "~0.7",
"grunt-nodemon": "~0.1",
"jsdom": "~0.8",
"proclaim": "~2.0",
"request": "~2.27"
}, },
"scripts": { "scripts": {

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
$(document).ready(function(){ $(document).ready(function(){
var data = {}; var data = {};
@@ -17,8 +32,13 @@ $(document).ready(function(){
hoverable: true hoverable: true
}, },
xaxis: { xaxis: {
mode: 'categories', mode: 'time',
tickLength: 0 tickLength: 0,
minTickSize: [1, 'day'],
timeformat: '%d %b'
},
yaxis: {
tickDecimals: 0
}, },
lines: { lines: {
lineWidth: 3 lineWidth: 3
@@ -112,7 +132,7 @@ $(document).ready(function(){
} }
function getXAxisLabel (el) { function getXAxisLabel (el) {
return el.find('[data-role="category"]').html(); return el.find('[data-role="date"]').attr('data-value');
} }
function storeDatum (el, label) { function storeDatum (el, label) {
@@ -167,12 +187,20 @@ $(document).ready(function(){
$.each(datasets, function(key, val) { $.each(datasets, function(key, val) {
var lowerCaseValue = (val.label.substring(0, val.label.length - 1)).toLowerCase(); var lowerCaseValue = (val.label.substring(0, val.label.length - 1)).toLowerCase();
choiceContainer.append('<li class="text-center '+ choiceContainer.append(
lowerCaseValue +'"><div class="series-checkbox-container"><input type="checkbox" name="' + key + '<li class="text-center ' + lowerCaseValue + '">' +
'" checked="checked" id="id' + key + '<div class="series-checkbox-container">' +
'"/><label for="id' + key + '<input type="checkbox"' +
'"><span class="stat-type">' + val.label + 'name="' + key + '" ' +
'</span></label></div></li>'); 'checked="checked" ' +
'id="id' + key + '"' +
'/>' +
'<label for="id' + key + '">' +
'<span class="stat-type">' + val.label + '</span>' +
'</label>' +
'</div>' +
'</li>'
);
}); });
choiceContainer.find('input').click(plotAccordingToChoices); choiceContainer.find('input').click(plotAccordingToChoices);
@@ -192,7 +220,7 @@ $(document).ready(function(){
} }
function showTooltip(x, y, contents) { function showTooltip(x, y, contents) {
$('<div data-role="tooltip" class="tooltip in"><div class="tooltip-inner">' + $('<div data-role="tooltip" class="tooltip tooltip-graph in"><div class="tooltip-inner">' +
contents + contents +
'</div></div>').css({top: y + 5,left: x + 5}).appendTo('body').fadeIn(200); '</div></div>').css({top: y + 5,left: x + 5}).appendTo('body').fadeIn(200);
} }
@@ -203,8 +231,13 @@ $(document).ready(function(){
if (previousPoint != item.dataIndex) { if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex; previousPoint = item.dataIndex;
$('[data-role="tooltip"]').remove(); $('[data-role="tooltip"]').remove();
var y = item.datapoint[1].toFixed(0); var count = item.datapoint[1].toFixed(0);
var contents = '<h6 class="crunch">' + y + ' ' + item.series.label + '</h6>'; var date = $.plot.formatDate(new Date(item.datapoint[0]), '%d %b' +
'<small> (%H:%M)</small>');
var contents = '<p class="crunch">' +
date + '<br/>' +
count + ' ' + item.series.label +
'</[h6]>';
showTooltip(item.pageX, item.pageY, contents); showTooltip(item.pageX, item.pageY, contents);
} }
} else { } else {
@@ -212,4 +245,45 @@ $(document).ready(function(){
previousPoint = null; previousPoint = null;
} }
}); });
// Task filter
function initTaskFilter (container) {
var tasks = initTaskFilterTasks(container);
var input = initTaskFilterInput(container, tasks);
}
function initTaskFilterTasks (container) {
var tasks = container.find('[data-role=task]');
return tasks;
}
function initTaskFilterInput (container, tasks) {
var input = container.find('[data-role=input]');
input.on('keyup', function () {
filterTasks(tasks, input.val());
});
return input;
}
function filterTasks (tasks, query) {
query = $.trim(query.replace(/[^a-z0-9\s]+/gi, ''));
tasks.removeClass('hidden');
if (/^\s*$/.test(query)) {
return;
}
var queryRegExp = new RegExp('(' + query.replace(/\s+/gi, '|') + ')', 'i');
tasks.filter(function () {
return !queryRegExp.test($(this).data('keywords'));
}).addClass('hidden');
}
var taskLists = $('[data-control=task-list]');
if (taskLists.length > 0) {
$('[data-control=task-list]').each(function () {
initTaskFilter($(this));
});
}
}); });

File diff suppressed because one or more lines are too long

93
public/less/ie8and.less Normal file
View File

@@ -0,0 +1,93 @@
// Making up for the non support of IE8 and IE7 in Bootstrap 3
// Amend the width of container if you want to here
@container-md-ie8: @container-md;
@grid-adjustment: percentage(@grid-gutter-width / @container-md-ie8);
.ie7, .ie8 {
* {
box-sizing: content-box;
}
.clearfix {
*zoom: 1;
}
ul, ol {
margin-left:0;
}
.container {
width: @container-md-ie8;
}
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11 {
float: left;
}
.col-md-1 { width: percentage((1 / @grid-columns)) - @grid-adjustment; }
.col-md-2 { width: percentage((2 / @grid-columns)) - @grid-adjustment; }
.col-md-3 { width: percentage((3 / @grid-columns)) - @grid-adjustment; }
.col-md-4 { width: percentage((4 / @grid-columns)) - @grid-adjustment; }
.col-md-5 { width: percentage((5 / @grid-columns)) - @grid-adjustment; }
.col-md-6 { width: percentage((6 / @grid-columns)) - @grid-adjustment; }
.col-md-7 { width: percentage((7 / @grid-columns)) - @grid-adjustment; }
.col-md-8 { width: percentage((8 / @grid-columns)) - @grid-adjustment; }
.col-md-9 { width: percentage((9 / @grid-columns)) - @grid-adjustment; }
.col-md-10 { width: percentage((10/ @grid-columns)) - @grid-adjustment; }
.col-md-11 { width: percentage((11/ @grid-columns)) - @grid-adjustment; }
.col-md-12 { width: 100% - @grid-adjustment; }
// Push and pull columns for source order changes
.col-md-push-0 { left: auto; }
.col-md-push-1 { left: percentage((1 / @grid-columns)); }
.col-md-push-2 { left: percentage((2 / @grid-columns)); }
.col-md-push-3 { left: percentage((3 / @grid-columns)); }
.col-md-push-4 { left: percentage((4 / @grid-columns)); }
.col-md-push-5 { left: percentage((5 / @grid-columns)); }
.col-md-push-6 { left: percentage((6 / @grid-columns)); }
.col-md-push-7 { left: percentage((7 / @grid-columns)); }
.col-md-push-8 { left: percentage((8 / @grid-columns)); }
.col-md-push-9 { left: percentage((9 / @grid-columns)); }
.col-md-push-10 { left: percentage((10/ @grid-columns)); }
.col-md-push-11 { left: percentage((11/ @grid-columns)); }
.col-md-pull-0 { right: auto; }
.col-md-pull-1 { right: percentage((1 / @grid-columns)); }
.col-md-pull-2 { right: percentage((2 / @grid-columns)); }
.col-md-pull-3 { right: percentage((3 / @grid-columns)); }
.col-md-pull-4 { right: percentage((4 / @grid-columns)); }
.col-md-pull-5 { right: percentage((5 / @grid-columns)); }
.col-md-pull-6 { right: percentage((6 / @grid-columns)); }
.col-md-pull-7 { right: percentage((7 / @grid-columns)); }
.col-md-pull-8 { right: percentage((8 / @grid-columns)); }
.col-md-pull-9 { right: percentage((9 / @grid-columns)); }
.col-md-pull-10 { right: percentage((10/ @grid-columns)); }
.col-md-pull-11 { right: percentage((11/ @grid-columns)); }
// Offsets
.col-md-offset-0 { margin-left: 0; }
.col-md-offset-1 { margin-left: percentage((1 / @grid-columns)); }
.col-md-offset-2 { margin-left: percentage((2 / @grid-columns)); }
.col-md-offset-3 { margin-left: percentage((3 / @grid-columns)); }
.col-md-offset-4 { margin-left: percentage((4 / @grid-columns)); }
.col-md-offset-5 { margin-left: percentage((5 / @grid-columns)); }
.col-md-offset-6 { margin-left: percentage((6 / @grid-columns)); }
.col-md-offset-7 { margin-left: percentage((7 / @grid-columns)); }
.col-md-offset-8 { margin-left: percentage((8 / @grid-columns)); }
.col-md-offset-9 { margin-left: percentage((9 / @grid-columns)); }
.col-md-offset-10 { margin-left: percentage((10/ @grid-columns)); }
.col-md-offset-11 { margin-left: percentage((11/ @grid-columns)); }
.clearfix {
*zoom: 1;
}
}

View File

@@ -58,4 +58,5 @@
@import "site-responsive.less"; @import "site-responsive.less";
// Stupid ie // Stupid ie
@import "ie8and.less";
@import "site-ie8and.less"; @import "site-ie8and.less";

View File

@@ -1,75 +1,20 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
// Making up for the non support of IE8 and IE7 in Bootstrap 3 // Making up for the non support of IE8 and IE7 in Bootstrap 3
.ie7, .ie8 { .ie7, .ie8 {
.container {
width: @container-md;
}
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11 {
float: left;
}
.col-md-1 { width: percentage((1 / @grid-columns)); }
.col-md-2 { width: percentage((2 / @grid-columns)); }
.col-md-3 { width: percentage((3 / @grid-columns)); }
.col-md-4 { width: percentage((4 / @grid-columns)); }
.col-md-5 { width: percentage((5 / @grid-columns)); }
.col-md-6 { width: percentage((6 / @grid-columns)); }
.col-md-7 { width: percentage((7 / @grid-columns)); }
.col-md-8 { width: percentage((8 / @grid-columns)); }
.col-md-9 { width: percentage((9 / @grid-columns)); }
.col-md-10 { width: percentage((10/ @grid-columns)); }
.col-md-11 { width: percentage((11/ @grid-columns)); }
.col-md-12 { width: 100%; }
// Push and pull columns for source order changes
.col-md-push-0 { left: auto; }
.col-md-push-1 { left: percentage((1 / @grid-columns)); }
.col-md-push-2 { left: percentage((2 / @grid-columns)); }
.col-md-push-3 { left: percentage((3 / @grid-columns)); }
.col-md-push-4 { left: percentage((4 / @grid-columns)); }
.col-md-push-5 { left: percentage((5 / @grid-columns)); }
.col-md-push-6 { left: percentage((6 / @grid-columns)); }
.col-md-push-7 { left: percentage((7 / @grid-columns)); }
.col-md-push-8 { left: percentage((8 / @grid-columns)); }
.col-md-push-9 { left: percentage((9 / @grid-columns)); }
.col-md-push-10 { left: percentage((10/ @grid-columns)); }
.col-md-push-11 { left: percentage((11/ @grid-columns)); }
.col-md-pull-0 { right: auto; }
.col-md-pull-1 { right: percentage((1 / @grid-columns)); }
.col-md-pull-2 { right: percentage((2 / @grid-columns)); }
.col-md-pull-3 { right: percentage((3 / @grid-columns)); }
.col-md-pull-4 { right: percentage((4 / @grid-columns)); }
.col-md-pull-5 { right: percentage((5 / @grid-columns)); }
.col-md-pull-6 { right: percentage((6 / @grid-columns)); }
.col-md-pull-7 { right: percentage((7 / @grid-columns)); }
.col-md-pull-8 { right: percentage((8 / @grid-columns)); }
.col-md-pull-9 { right: percentage((9 / @grid-columns)); }
.col-md-pull-10 { right: percentage((10/ @grid-columns)); }
.col-md-pull-11 { right: percentage((11/ @grid-columns)); }
// Offsets
.col-md-offset-0 { margin-left: 0; }
.col-md-offset-1 { margin-left: percentage((1 / @grid-columns)); }
.col-md-offset-2 { margin-left: percentage((2 / @grid-columns)); }
.col-md-offset-3 { margin-left: percentage((3 / @grid-columns)); }
.col-md-offset-4 { margin-left: percentage((4 / @grid-columns)); }
.col-md-offset-5 { margin-left: percentage((5 / @grid-columns)); }
.col-md-offset-6 { margin-left: percentage((6 / @grid-columns)); }
.col-md-offset-7 { margin-left: percentage((7 / @grid-columns)); }
.col-md-offset-8 { margin-left: percentage((8 / @grid-columns)); }
.col-md-offset-9 { margin-left: percentage((9 / @grid-columns)); }
.col-md-offset-10 { margin-left: percentage((10/ @grid-columns)); }
.col-md-offset-11 { margin-left: percentage((11/ @grid-columns)); }
.legend { .legend {
display: block; display: block;
width: 100%; width: 100%;
@@ -83,14 +28,11 @@
.tooltip-inner { .tooltip-inner {
background-color: #000000; background-color: #000000;
} }
.clearfix {
*zoom: 1;
}
.date { .date {
font-size:85%; font-size:85%;
} }
.task-card-link { .task-card-link {
min-height:190px; min-height:160px;
} }
.series-checkboxes li { .series-checkboxes li {
margin-right:1%; margin-right:1%;
@@ -98,34 +40,41 @@
.stat-type { .stat-type {
font-size:floor(@font-size-base * 0.65); // ~10px; font-size:floor(@font-size-base * 0.65); // ~10px;
} }
}
.ie7 {
ul {
margin-left:0;
}
.col-md-2 { width:14%; }
.col-md-3 { width:22%; }
.col-md-4 {
width: 32%;
padding:0 5px;
}
.col-md-9 { width:72%; }
.col-md-10 { width:80%; }
.col-md-12 { width: 97%; }
.aside .task-stats li {
width:31.5%;
}
.aside .action-buttons .btn { .aside .action-buttons .btn {
width:79%; width:79%;
} }
.date-selector { .pull-right.dropdown-menu {
zoom:1; right:134px;
}
.run-details .pull-right.dropdown-menu {
right:64px;
}
.date-selector .btn-full-width {
width:90%;
}
.filter-toggle {
&:before {
height:110%;
width:100%;
left:0;
top:0;
}
input {
width:92%;
}
.filter-trigger {
padding-bottom:0;
}
}
}
.ie7 {
.aside .task-stats li {
width:31.5%;
} }
.zfix { .zfix {
position:relative; position:relative;
z-index:100; z-index:1001;
} }
.list-group li .list-group-item { .list-group li .list-group-item {
margin:0; margin:0;
@@ -136,6 +85,44 @@
padding-bottom:90px; padding-bottom:90px;
} }
.date-selector { .date-selector {
margin-top:-155px; zoom:1;
.btn-full-width {
width:100%;
}
}
.sr-only {
position:relative;
}
.breadcrumb li {
vertical-align: top;
zoom: 1;
display: inline;
margin-right:10px;
}
.pull-right.dropdown-menu {
right:0px;
}
.run-details .pull-right.dropdown-menu {
right:82px;
}
.tasks-list li {
padding-right:105px;
}
.filter-toggle {
width:30%;
margin:0 35%;
margin-top:-10px;
background-color:lighten(@gray-lighter, 4%);
padding-bottom:10px;
.glyphicon {
display:none;
}
input {
width:80%;
margin-left:-25%;
}
} }
} }

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* No javascript */ /* No javascript */
.no-javascript { .no-javascript {
.graph-container, .expander { .graph-container, .expander {
@@ -10,7 +25,7 @@
.date-links.hidden { .date-links.hidden {
display:none !important; display:none !important;
} }
.date-selector .btn-group:hover ul.date-links { .btn-group:hover ul {
display:block !important; display:block !important;
} }
table.hidden { table.hidden {
@@ -26,4 +41,7 @@
.show-class { .show-class {
display:block; display:block;
} }
.no-js-hide {
display: none;
}
} }

View File

@@ -1,9 +1,19 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* Media queries */ /* Media queries */
@media (max-width:1199px) {
.task-card .task-card-link {
min-height:215px;
}
}
@media (max-width:991px) { @media (max-width:991px) {
.h1, h1 { .h1, h1 {
font-size:floor(@font-size-base * 2.15); // ~32px; font-size:floor(@font-size-base * 2.15); // ~32px;
@@ -11,9 +21,6 @@
.h2, h2 { .h2, h2 {
font-size:floor(@font-size-base * 1.9); // ~28px; font-size:floor(@font-size-base * 1.9); // ~28px;
} }
.task-card .task-card-link {
min-height:200px;
}
.task-header .h4 { .task-header .h4 {
font-size:floor(@font-size-base * 1.15); // ~17px; font-size:floor(@font-size-base * 1.15); // ~17px;
} }
@@ -36,11 +43,16 @@
.other-tasks { .other-tasks {
.sr-only(); .sr-only();
} }
.action-buttons,
.task-stats, .task-stats,
.btn-full-width { .btn-full-width {
margin-bottom:0; margin-bottom:0;
} }
.task-card .task-stats {
margin-bottom:10px;
}
.action-buttons {
margin-bottom:20px;
}
.aside { .aside {
margin-bottom:15px; margin-bottom:15px;
} }
@@ -54,7 +66,7 @@
float:none; float:none;
li { li {
width:33%; width:25%;
} }
} }
} }
@@ -75,6 +87,7 @@
} }
.action-buttons { .action-buttons {
margin-top:10px; margin-top:10px;
margin-bottom:0;
.btn-full-width { .btn-full-width {
margin-bottom:10px; margin-bottom:10px;
@@ -85,6 +98,9 @@
text-align:left; text-align:left;
} }
} }
.task-card .task-card-link {
min-height:0;
}
} }
@media (max-width:640px) { @media (max-width:640px) {
body { body {
@@ -126,6 +142,11 @@
margin-bottom:20px; margin-bottom:20px;
} }
} }
.footer .nav {
li {
width:50%;
}
}
} }
@media (max-width:479px) { @media (max-width:479px) {
.graph { .graph {

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* Site specific styling */ /* Site specific styling */
/* Helper Classes */ /* Helper Classes */
@@ -70,7 +85,7 @@
} }
.dropdown-toggle { .dropdown-toggle {
margin-top:0; margin-top:0;
margin-bottom:10px; margin-bottom:5px;
} }
.list-group { .list-group {
li .list-group-item { li .list-group-item {
@@ -87,14 +102,10 @@
margin-bottom:0; margin-bottom:0;
} }
} }
.delete-button { .options-button {
position:absolute; position:absolute;
top:5px; top:5px;
right:20px; right:20px;
color:@brand-danger;
}
.delete-button:hover {
color:lighten(@brand-danger, 8%);
} }
.footer a, .breadcrumb a { .footer a, .breadcrumb a {
text-decoration:underline; text-decoration:underline;
@@ -183,15 +194,15 @@
} }
.task-card-link { .task-card-link {
color:@gray-dark; color:@gray-dark;
min-height:200px; min-height:190px;
display:block; display:block;
transition: background 0.5s; transition: background 0.5s;
-webkit-transition: background 0.5s; -webkit-transition: background 0.5s;
} }
.delete-button { .options-button {
display:none; display:none;
} }
&:hover .delete-button { &:hover .options-button {
display:block; display:block;
} }
.task-card-link:hover, .task-card-link:hover,
@@ -211,14 +222,15 @@
text-align:center; text-align:center;
color:@badge-color; color:@badge-color;
} }
.dropdown-menu {
top:25px;
}
} }
/* Badges */ /* Badges */
.badge { .badge {
border-radius:0.25em; border-radius:0.25em;
}
.badge {
display:inline-block; display:inline-block;
padding:10px; padding:10px;
font-size:ceil(@font-size-base * 0.85); // ~13px; font-size:ceil(@font-size-base * 0.85); // ~13px;
@@ -239,6 +251,9 @@
h2 { h2 {
word-wrap:break-word; word-wrap:break-word;
} }
.h4 {
margin-bottom:22px;
}
} }
.date { .date {
margin-top:5px; margin-top:5px;
@@ -254,10 +269,27 @@
li { li {
margin-bottom:20px; margin-bottom:20px;
padding-right:90px;
position:relative;
&:last-child { &:last-child {
margin-bottom:0; margin-bottom:0;
} }
form {
display:none;
position:absolute;
right:0;
top:0;
&:hover .btn {
color:@brand-primary;
}
}
&:hover form {
display:block;
}
} }
.rule-name { .rule-name {
@@ -265,6 +297,7 @@
font-style:italic; font-style:italic;
word-wrap:break-word; word-wrap:break-word;
} }
} }
.task-danger { .task-danger {
border-color:@brand-danger; border-color:@brand-danger;
@@ -321,7 +354,7 @@ ul.date-links {
} }
&.single-result { &.single-result {
margin-top:-55px; margin-top:-52px;
.show-stats { .show-stats {
display:none; display:none;
@@ -383,6 +416,14 @@ ul.date-links {
margin-top:-24px; margin-top:-24px;
margin-right:35px margin-right:35px
} }
.flot-x-axis {
.flot-tick-label {
max-width:45px !important;
}
}
.tooltip-graph {
font-size:12px;
}
/* New task page */ /* New task page */
.standards-lists { .standards-lists {
@@ -407,7 +448,33 @@ ul.date-links {
} }
} }
/* Sidebar */ .filter-toggle {
.action-buttons { top:-20px;
margin-bottom:30px; margin-top:-10px;
font-size:18px;
font-weight:bold;
.filter-trigger {
padding-bottom:20px;
cursor: pointer;
.glyphicon {
display:block;
margin:0 auto;
}
}
&:before {
position:absolute;
content:"";
height:90px;
width:90px;
left:50%;
top:-45px;
background-color:lighten(@gray-lighter, 4%);
transform: translateX(-50%) rotate(45deg);
-ms-transform: translateX(-50%) rotate(45deg);
-webkit-transform: translateX(-50%) rotate(45deg);
z-index:-1;
}
} }

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var presentTask = require('../view/presenter/task'); var presentTask = require('../view/presenter/task');

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var getStandards = require('../data/standards'); var getStandards = require('../data/standards');

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var moment = require('moment'); var moment = require('moment');
@@ -46,13 +61,13 @@ function route (app) {
app.express.get('/:id/:rid.csv', getTaskAndResult, function (req, res) { app.express.get('/:id/:rid.csv', getTaskAndResult, function (req, res) {
var task = res.locals.task; var task = res.locals.task;
var result = res.locals.result; var result = res.locals.result;
var rows = ['"code", "message", "type"']; var rows = ['"code","message","type"'];
result.results.forEach(function (msg) { result.results.forEach(function (msg) {
rows.push([ rows.push([
JSON.stringify(msg.code), JSON.stringify(msg.code),
JSON.stringify(msg.message), JSON.stringify(msg.message),
JSON.stringify(msg.type) JSON.stringify(msg.type)
].join(', ')); ].join(','));
}); });
res.attachment(getDownloadFileName(task, result, 'csv')); res.attachment(getDownloadFileName(task, result, 'csv'));
res.send(rows.join('\n')); res.send(rows.join('\n'));

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var presentTask = require('../../view/presenter/task'); var presentTask = require('../../view/presenter/task');

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var _ = require('underscore'); var _ = require('underscore');
@@ -15,7 +30,7 @@ function route (app) {
} }
res.render('task/delete', { res.render('task/delete', {
task: presentTask(task), task: presentTask(task),
isTaskPage: true isTaskSubPage: true
}); });
}); });
}); });

87
route/task/edit.js Normal file
View File

@@ -0,0 +1,87 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict';
var _ = require('underscore');
var presentTask = require('../../view/presenter/task');
var getStandards = require('../../data/standards');
module.exports = route;
// Route definition
function route (app) {
app.express.get('/:id/edit', function (req, res, next) {
app.webservice.task(req.params.id).get({}, function (err, task) {
if (err) {
return next();
}
var standards = getStandards().map(function (standard) {
if (standard.title === task.standard) {
standard.selected = true;
}
standard.rules = standard.rules.map(function (rule) {
if (task.ignore.indexOf(rule.name) !== -1) {
rule.ignored = true;
}
return rule;
});
return standard;
});
res.render('task/edit', {
edited: (typeof req.query.edited !== 'undefined'),
standards: standards,
task: presentTask(task),
isTaskSubPage: true
});
});
});
app.express.post('/:id/edit', function (req, res, next) {
app.webservice.task(req.params.id).get({}, function (err, task) {
if (err) {
return next();
}
req.body.ignore = req.body.ignore || [];
app.webservice.task(req.params.id).edit(req.body, function (err) {
if (err) {
task.name = req.body.name;
task.ignore = req.body.ignore;
var standards = getStandards().map(function (standard) {
if (standard.title === task.standard) {
standard.selected = true;
}
standard.rules = standard.rules.map(function (rule) {
if (task.ignore.indexOf(rule.name) !== -1) {
rule.ignored = true;
}
return rule;
});
return standard;
});
return res.render('task/edit', {
error: err,
standards: standards,
task: task,
isTaskSubPage: true
});
}
res.redirect('/' + req.params.id + '/edit?edited');
});
});
});
}

30
route/task/ignore.js Normal file
View File

@@ -0,0 +1,30 @@
'use strict';
var _ = require('underscore');
var presentTask = require('../../view/presenter/task');
var getStandards = require('../../data/standards');
module.exports = route;
// Route definition
function route (app) {
app.express.post('/:id/ignore', function (req, res, next) {
app.webservice.task(req.params.id).get({}, function (err, task) {
if (err) {
return next();
}
var edit = {
name: task.name,
ignore: task.ignore
};
if (typeof req.body.rule === 'string') {
edit.ignore.push(req.body.rule);
}
app.webservice.task(req.params.id).edit(edit, function () {
res.redirect('/' + req.params.id + '?rule-ignored');
});
});
});
}

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var presentTask = require('../../view/presenter/task'); var presentTask = require('../../view/presenter/task');
@@ -25,6 +40,8 @@ function route (app) {
mainResult: task.lastResult || null, mainResult: task.lastResult || null,
added: (typeof req.query.added !== 'undefined'), added: (typeof req.query.added !== 'undefined'),
running: (typeof req.query.running !== 'undefined'), running: (typeof req.query.running !== 'undefined'),
ruleIgnored: (typeof req.query['rule-ignored'] !== 'undefined'),
ruleUnignored: (typeof req.query['rule-unignored'] !== 'undefined'),
hasOneResult: (presentedResults.length < 2), hasOneResult: (presentedResults.length < 2),
isTaskPage: true isTaskPage: true
}); });

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
module.exports = route; module.exports = route;

31
route/task/unignore.js Normal file
View File

@@ -0,0 +1,31 @@
'use strict';
var _ = require('underscore');
var presentTask = require('../../view/presenter/task');
var getStandards = require('../../data/standards');
module.exports = route;
// Route definition
function route (app) {
app.express.post('/:id/unignore', function (req, res, next) {
app.webservice.task(req.params.id).get({}, function (err, task) {
if (err) {
return next();
}
var edit = {
name: task.name,
ignore: task.ignore
};
var indexOfRule = edit.ignore.indexOf(req.body.rule);
if (typeof req.body.rule === 'string' && indexOfRule !== -1) {
edit.ignore.splice(indexOfRule, 1);
}
app.webservice.task(req.params.id).edit(edit, function () {
res.redirect('/' + req.params.id + '?rule-unignored');
});
});
});
}

View File

@@ -0,0 +1,66 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict';
var jsdom = require('jsdom');
var request = require('request');
module.exports = createNavigator;
// Create a navigate function
function createNavigator (baseUrl, store) {
return function (opts, callback) {
store.body = null;
store.dom = null;
store.request = null;
store.response = null;
store.status = null;
store.window = null;
request({
url: baseUrl + opts.endpoint,
method: opts.method || 'GET',
body: opts.body,
json: true,
qs: opts.query,
followAllRedirects: true
}, function (err, res, body) {
store.body = body;
store.request = res.request;
store.response = res;
store.status = res.statusCode;
if (opts.nonDom) {
store.window = null;
store.dom = null;
callback();
} else {
jsdom.env(
store.body,
function (err, window) {
store.window = window;
store.dom = window.document;
callback();
}
);
}
});
};
}

View File

@@ -0,0 +1,29 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict';
var createClient = require('pa11y-webservice-client-node');
module.exports = createWebserviceClient;
// Create a webservice client
function createWebserviceClient (config) {
var webserviceUrl = config.webservice;
if (typeof webserviceUrl == 'object') {
webserviceUrl = 'http://' + webserviceUrl.host + ':' + webserviceUrl.port + '/';
}
return createClient(webserviceUrl);
}

View File

@@ -0,0 +1,94 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should display an "Add new URL" button', function () {
var elem = this.last.dom.querySelectorAll('[data-test=add-task]');
assert.strictEqual(elem.length, 1);
assert.strictEqual(elem[0].getAttribute('href'), '/new');
});
it('should display all of the expected tasks', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.strictEqual(tasks.length, 3);
assert.match(tasks[0].textContent, /npg home\s+\(wcag2aa\)/i);
assert.match(tasks[1].textContent, /npg home\s+\(wcag2aaa\)/i);
assert.match(tasks[2].textContent, /nature news\s+\(section508\)/i);
});
it('should have links to each task', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001"]').length, 1);
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002"]').length, 1);
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003"]').length, 1);
});
it('should display an "Edit" button for each task', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001/edit"]').length, 1);
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002/edit"]').length, 1);
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003/edit"]').length, 1);
});
it('should display a "Delete" button for each task', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001/delete"]').length, 1);
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002/delete"]').length, 1);
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003/delete"]').length, 1);
});
it('should display a "Run" button for each task', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001/run"]').length, 1);
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002/run"]').length, 1);
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003/run"]').length, 1);
});
it('should display the task result counts if the task has been run', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.match(tasks[0].textContent, /1\s*errors/i);
assert.match(tasks[0].textContent, /2\s*warnings/i);
assert.match(tasks[0].textContent, /3\s*notices/i);
});
it('should display a message indicating that there are no results if the task has not been run', function () {
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
assert.match(tasks[2].textContent, /no results/i);
});
it('should not display an alert message', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=alert]').length, 0);
});
});

View File

@@ -0,0 +1,151 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /new', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/new'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should not display an error message', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 0);
});
it('should have an "Add new URL" form', function () {
var form = this.last.dom.querySelectorAll('[data-test=new-url-form]')[0];
assert.isDefined(form);
assert.strictEqual(form.getAttribute('action'), '/new');
assert.strictEqual(form.getAttribute('method'), 'post');
});
describe('"Add New URL" form', function () {
beforeEach(function () {
this.form = this.last.dom.querySelectorAll('[data-test=new-url-form]')[0];
});
it('should have a "name" field', function () {
var field = this.form.querySelectorAll('input[name=name]')[0];
assert.isDefined(field);
assert.strictEqual(field.getAttribute('type'), 'text');
assert.strictEqual(field.getAttribute('value'), '');
});
it('should have a "url" field', function () {
var field = this.form.querySelectorAll('input[name=url]')[0];
assert.isDefined(field);
assert.strictEqual(field.getAttribute('type'), 'url');
assert.strictEqual(field.getAttribute('value'), '');
});
it('should have a "standard" field', function () {
var field = this.form.querySelectorAll('select[name=standard]')[0];
assert.isDefined(field);
assert.strictEqual(field.querySelectorAll('option').length, 4);
});
it('should have "ignore" fields', function () {
var fields = this.form.querySelectorAll('input[name="ignore[]"]');
assert.isDefined(fields);
assert.notStrictEqual(fields.length, 0);
});
});
});
describe('POST /new', function () {
describe('with invalid query', function () {
beforeEach(function (done) {
var req = {
method: 'POST',
endpoint: '/new',
body: {
name: '',
url: ''
}
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should display an error message', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 1);
});
});
describe('with valid query', function () {
beforeEach(function (done) {
var req = {
method: 'POST',
endpoint: '/new',
body: {
name: 'Example',
url: 'http://example.com/',
standard: 'WCAG2AA'
}
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should create the task', function (done) {
this.webservice.tasks.get({}, function (err, tasks) {
assert.strictEqual(tasks.length, 4);
done();
});
});
it('should redirect me to the new URL page', function () {
assert.match(this.last.request.uri.pathname, /^\/[a-z0-9]{24}$/i);
});
it('should not display an error message', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 0);
});
it('should display a success message', function () {
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
assert.isDefined(alert);
assert.match(alert.textContent, /url has been added/i);
});
});
});

View File

@@ -0,0 +1,68 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>/<result-id>.csv', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/def000000000000000000001.csv',
nonDom: true
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should output CSV results', function () {
assert.match(this.last.body, /^"code","message","type"/);
});
});
describe('GET /<task-id>/<result-id>.json', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/def000000000000000000001.json',
nonDom: true
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should output JSON results', function () {
var json = this.last.body;
assert.strictEqual(json.task.name, 'NPG Home');
assert.strictEqual(json.task.url, 'nature.com');
assert.strictEqual(json.count.error, 1);
assert.strictEqual(json.count.warning, 2);
assert.strictEqual(json.count.notice, 3);
assert.isArray(json.results);
});
});

View File

@@ -0,0 +1,70 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>/<result-id>', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/def000000000000000000001'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should display a "Download CSV" button', function () {
var elem = this.last.dom.querySelectorAll('[data-test=download-csv]');
assert.strictEqual(elem.length, 1);
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.csv');
});
it('should display a "Download JSON" button', function () {
var elem = this.last.dom.querySelectorAll('[data-test=download-json]');
assert.strictEqual(elem.length, 1);
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.json');
});
it('should display a link back to the task', function () {
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001"]')[0]);
});
it('should display errors', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-errors]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /errors \( 1 \)/i);
});
it('should display warnings', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-warnings]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /warnings \( 2 \)/i);
});
it('should display notices', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-notices]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /notices \( 3 \)/i);
});
});

View File

@@ -0,0 +1,80 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>/delete', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/delete'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should have a "Delete URL" form', function () {
var form = this.last.dom.querySelectorAll('[data-test=delete-url-form]')[0];
assert.isDefined(form);
assert.strictEqual(form.getAttribute('action'), '/abc000000000000000000001/delete');
assert.strictEqual(form.getAttribute('method'), 'post');
});
it('should display a link back to the task page', function () {
assert.greaterThan(this.last.dom.querySelectorAll('[href="/abc000000000000000000001"]').length, 0);
});
});
describe('POST /<task-id>/delete', function () {
beforeEach(function (done) {
var req = {
method: 'POST',
endpoint: '/abc000000000000000000001/delete'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should delete the task', function (done) {
this.webservice.task('abc000000000000000000001').get({}, function (err) {
assert.strictEqual(err.message, 'Error 404');
done();
});
});
it('should redirect me to the home page', function () {
assert.strictEqual(this.last.request.uri.pathname, '/');
});
it('should display a success message', function () {
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
assert.isDefined(alert);
assert.match(alert.textContent, /been deleted/i);
});
});

View File

@@ -0,0 +1,117 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>/edit', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/edit'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should have an "Edit URL" form', function () {
var form = this.last.dom.querySelectorAll('[data-test=edit-url-form]')[0];
assert.isDefined(form);
assert.strictEqual(form.getAttribute('action'), '/abc000000000000000000001/edit');
assert.strictEqual(form.getAttribute('method'), 'post');
});
it('should display a link back to the task page', function () {
assert.greaterThan(this.last.dom.querySelectorAll('[href="/abc000000000000000000001"]').length, 0);
});
describe('"Edit URL" form', function () {
beforeEach(function () {
this.form = this.last.dom.querySelectorAll('[data-test=edit-url-form]')[0];
});
it('should have a "name" field', function () {
var field = this.form.querySelectorAll('input[name=name]')[0];
assert.isDefined(field);
assert.strictEqual(field.getAttribute('type'), 'text');
assert.strictEqual(field.getAttribute('value'), 'NPG Home');
});
it('should have a disabled "url" field', function () {
var field = this.form.querySelectorAll('input[name=url]')[0];
assert.isDefined(field);
assert.strictEqual(field.getAttribute('type'), 'url');
assert.strictEqual(field.getAttribute('value'), 'nature.com');
assert.isDefined(field.getAttribute('disabled'));
});
it('should have a disabled "standard" field', function () {
var field = this.form.querySelectorAll('select[name=standard]')[0];
assert.isDefined(field);
assert.isDefined(field.getAttribute('disabled'));
});
it('should have "ignore" fields', function () {
var fields = this.form.querySelectorAll('input[name="ignore[]"]');
assert.isDefined(fields);
assert.notStrictEqual(fields.length, 0);
});
});
});
describe('POST /<task-id>/edit', function () {
beforeEach(function (done) {
var req = {
method: 'POST',
endpoint: '/abc000000000000000000001/edit',
body: {
name: 'foo',
ignore: ['bar', 'baz']
}
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should edit the task', function (done) {
this.webservice.task('abc000000000000000000001').get({}, function (err, task) {
assert.strictEqual(task.name, 'foo');
assert.deepEqual(task.ignore, ['bar', 'baz']);
done();
});
});
it('should display a success message', function () {
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
assert.isDefined(alert);
assert.match(alert.textContent, /been saved/i);
});
});

View File

@@ -0,0 +1,111 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>', function () {
describe('when task has results', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should display an "Edit" button', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/edit"]').length, 1);
});
it('should display a "Delete" button', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/delete"]').length, 1);
});
it('should display a "Run" button', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/run"]').length, 1);
});
it('should display a "Download CSV" button for the latest result', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000001.csv"]').length, 1);
});
it('should display a "Download JSON" button for the latest result', function () {
assert.strictEqual(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000001.json"]').length, 1);
});
it('should display links to all results', function () {
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000001"]')[0]);
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000003"]')[0]);
});
it('should display errors', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-errors]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /errors \( 1 \)/i);
});
it('should display warnings', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-warnings]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /warnings \( 2 \)/i);
});
it('should display notices', function () {
var elem = this.last.dom.querySelectorAll('[data-test=task-notices]')[0];
assert.isDefined(elem);
assert.match(elem.textContent, /notices \( 3 \)/i);
});
});
describe('when task has no results', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000003'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should display a "Run" button', function () {
var elem = this.last.dom.querySelectorAll('[data-test=run-task]');
assert.strictEqual(elem.length, 1);
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000003/run');
});
it('should display a message indicating that there are no results', function () {
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
assert.isDefined(alert);
assert.match(alert.textContent, /there are no results to show/i);
});
});
});

View File

@@ -0,0 +1,46 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global beforeEach, describe, it */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var assert = require('proclaim');
describe('GET /<task-id>/run', function () {
beforeEach(function (done) {
var req = {
method: 'GET',
endpoint: '/abc000000000000000000001/run'
};
this.navigate(req, done);
});
it('should send a 200 status', function () {
assert.strictEqual(this.last.status, 200);
});
it('should redirect me to the task page', function () {
assert.strictEqual(this.last.request.uri.pathname, '/abc000000000000000000001');
});
it('should display a success message', function () {
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
assert.isDefined(alert);
assert.match(alert.textContent, /new results are being generated/i);
});
});

51
test/functional/setup.js Normal file
View File

@@ -0,0 +1,51 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
/* global afterEach, before */
/* jshint maxlen: false, maxstatements: false */
'use strict';
var config = require('../../config/test.json');
var createNavigator = require('./helper/navigate');
var createWebserviceClient = require('./helper/webservice');
var loadFixtures = require('pa11y-webservice/data/fixture/load');
var request = require('request');
// Run before all tests
before(function (done) {
this.baseUrl = 'http://localhost:' + config.port;
this.last = {};
this.navigate = createNavigator(this.baseUrl, this.last);
this.webservice = createWebserviceClient(config);
assertTestAppIsRunning(this.baseUrl, function () {
loadFixtures('test', config.webservice, done);
});
});
// Run after each test
afterEach(function (done) {
loadFixtures('test', config.webservice, done);
});
// Check that the test application is running, and exit if not
function assertTestAppIsRunning (url, done) {
request(url, function (err) {
if (err) {
console.error('Error: Test app not started; run with `grunt start-test`');
process.exit(1);
}
done();
});
}

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-8"> <div class="col-md-8">
<h1>Hmmm, this page indicates a 404 error.</h1> <h1>Hmmm, this page indicates a 404 error.</h1>
<p class="h2">That is techy babble for "We couldn't find the page you were looking for".</h2> <p class="h2">That is techy babble for "We couldn't find the page you were looking for".</h2>

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-8"> <div class="col-md-8">
<h1>Eeek! 500 error. This is serious.</h1> <h1>Eeek! 500 error. This is serious.</h1>
<p class="h2">There isn't much you can do about this.</h2> <p class="h2">There isn't much you can do about this.</h2>

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var moment = require('moment'); var moment = require('moment');
@@ -17,4 +32,9 @@ function helper (register) {
return moment(context).fromNow(); return moment(context).fromNow();
}); });
register('date-timestamp', function (context) {
return moment(context).valueOf();
});
} }

12
view/helper/string.js Normal file
View File

@@ -0,0 +1,12 @@
'use strict';
module.exports = helper;
function helper (register) {
// Convert a string to lower-case
register('lowercase', function (context) {
return context.toLowerCase();
});
}

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
module.exports = helper; module.exports = helper;
@@ -6,7 +21,7 @@ function helper (register) {
// Simplify url by removing (eg http://, https://, trailing slashes) from url // Simplify url by removing (eg http://, https://, trailing slashes) from url
register('simplify-url', function (context) { register('simplify-url', function (context) {
return context.replace(/^https?:\/\//i, '').replace(/\/$/, ''); return context.replace(/^https?:\/\//i, '').replace(/\/$/, '').toLowerCase();
}); });
} }

View File

@@ -1,7 +1,23 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}}pa11y-dashboard{{/content}} {{#content "title"}}pa11y-dashboard{{/content}}
{{#if siteMessage}} {{#if siteMessage}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-info site-message"> <div class="alert alert-info site-message">
<h3 class="crunch-top"><span class="pull-left glyphicon glyphicon-exclamation-sign"></span> Important</h3> <h3 class="crunch-top"><span class="pull-left glyphicon glyphicon-exclamation-sign"></span> Important</h3>
<p class="h5">{{siteMessage}}</p> <p class="h5">{{siteMessage}}</p>
@@ -10,7 +26,7 @@
{{/if}} {{/if}}
{{#deleted}} {{#deleted}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-info"> <div class="alert alert-info">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button> <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>Bye Bye URL</strong> <strong>Bye Bye URL</strong>

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{lang}}" class="no-javascript"> <html lang="{{lang}}" class="no-javascript">
<head> <head>
@@ -17,7 +33,7 @@
<meta name="viewport" content="width=device-width"/> <meta name="viewport" content="width=device-width"/>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lato:400,700,900,400italic"/> <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lato:400,700,900,400italic"/>
<link rel="stylesheet" href="/css/site.min.css"/> <link rel="stylesheet" href="/css/site.min.css?v={{version}}"/>
</head> </head>
<!--[if IE 7]><body class="ie7"><![endif]--> <!--[if IE 7]><body class="ie7"><![endif]-->
@@ -47,7 +63,7 @@
{{> page-footer}} {{> page-footer}}
<script type="text/javascript" src="/js/site.min.js"></script> <script type="text/javascript" src="/js/site.min.js?v={{version}}"></script>
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="/js/vendor/flot/excanvas.min.js"></script><![endif]--> <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="/js/vendor/flot/excanvas.min.js"></script><![endif]-->
</body> </body>

View File

@@ -1,16 +1,32 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}} {{#content "title"}}
Add a new URL Add a new URL
{{/content}} {{/content}}
<form role="form" class="col-md-12" action="/new" method="post"> <form role="form" class="col-md-12" action="/new" method="post" data-test="new-url-form">
<div class="legend"> <div class="legend">
<h1 class="h2 crunch-top">Add a new URL</h1> <h1 class="h2 crunch-top">Add a new URL</h1>
</div> </div>
{{#error}} {{#error}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix" data-test="error">
<div class="alert alert-danger"> <div class="alert alert-danger">
<strong>Oh my gosh!</strong> <strong>Oh my gosh!</strong>
<p>{{.}}</p> <p>{{.}}</p>

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#unless isHomePage}} {{#unless isHomePage}}
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -10,6 +26,9 @@
{{#if isTaskPage}} {{#if isTaskPage}}
<li class="active">{{task.name}}</li> <li class="active">{{task.name}}</li>
{{/if}} {{/if}}
{{#if isTaskSubPage}}
<li><a href="{{task.href}}">{{task.name}}</a></li>
{{/if}}
{{#if isResultPage}} {{#if isResultPage}}
<li><a href="{{task.href}}">{{task.name}}</a></li> <li><a href="{{task.href}}">{{task.name}}</a></li>
<li class="active">Results for {{date-format mainResult.date format="DD MMM YYYY"}}</li> <li class="active">Results for {{date-format mainResult.date format="DD MMM YYYY"}}</li>

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix">
<div class="graph-container graph-spacer ruled"> <div class="graph-container graph-spacer ruled">
<div data-role="graph" class="graph"></div> <div data-role="graph" class="graph"></div>
@@ -23,7 +39,7 @@
<tbody> <tbody>
{{#results}} {{#results}}
<tr data-role="url-stats"> <tr data-role="url-stats">
<td data-role="category">{{date-format date format="DD MMM YYYY"}}</td> <td data-value="{{date-timestamp date}}" data-role="date">{{date-format date format="DD MMM YYYY"}}</td>
<td class="text-center" data-label="error">{{count.error}}</td> <td class="text-center" data-label="error">{{count.error}}</td>
<td class="text-center" data-label="warning">{{count.warning}}</td> <td class="text-center" data-label="warning">{{count.warning}}</td>
<td class="text-center" data-label="notice">{{count.notice}}</td> <td class="text-center" data-label="notice">{{count.notice}}</td>

View File

@@ -1,10 +1,26 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<footer> <footer>
<div class="footer" role="contentinfo"> <div class="footer" role="contentinfo">
<div class="container"> <div class="container">
<div class="col-md-7"> <div class="col-md-5">
<small>&copy; {{year}} Nature Publishing Group.<br/>pa11y dashboard is licensed under the GNU General Public License 3.0.<br/>Version {{version}}</small> <small>&copy; {{year}} Nature Publishing Group.<br/>pa11y dashboard is licensed under the GNU General Public License 3.0.<br/>Version {{version}}</small>
</div> </div>
<div class="col-md-5 clearfix"> <div class="col-md-7 clearfix">
<ul class="crunch-bottom floated-list nav"> <ul class="crunch-bottom floated-list nav">
<li> <li>
<a href="{{repo}}">GitHub Repo</a> <a href="{{repo}}">GitHub Repo</a>
@@ -15,6 +31,9 @@
<li> <li>
<a href="http://www.w3.org/TR/WCAG20/">WCAG 2.0 spec</a> <a href="http://www.w3.org/TR/WCAG20/">WCAG 2.0 spec</a>
</li> </li>
<li>
<a href="http://squizlabs.github.io/HTML_CodeSniffer/">HTML_CodeSniffer</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<header> <header>
<div role="banner" class="header"> <div role="banner" class="header">
<div class="container"> <div class="container">

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-12"> <div class="col-md-12">
<div class="ruled task-header"> <div class="ruled task-header">
<div class="row clearfix"> <div class="row clearfix">

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-12 zfix"> <div class="col-md-12 zfix">
<div class="row"> <div class="row">
<div class="col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3"> <div class="col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3">

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-3 aside"> <div class="col-md-3 aside">
<div class="row"> <div class="row">
<div id="top" class="col-md-12 col-sm-6 col-xs-12"> <div id="top" class="col-md-12 col-sm-6 col-xs-12">
@@ -12,32 +28,31 @@
<div class="action-buttons col-md-12 col-sm-6 clearfix"> <div class="action-buttons col-md-12 col-sm-6 clearfix">
<div class="row"> <div class="row">
<div class="col-md-12 col-sm-6 col-xs-12"> <div class="col-md-12 col-sm-6 col-xs-12">
<a href="{{mainResult.hrefCsv}}" class="btn-full-width btn btn-default">Download CSV <span class="glyphicon glyphicon-download"></span></a> <a href="{{mainResult.hrefCsv}}" class="btn-full-width btn btn-default" data-test="download-csv">
Download CSV <span class="glyphicon glyphicon-download"></span>
</a>
</div> </div>
<div class="col-md-12 col-sm-6 col-xs-12"> <div class="col-md-12 col-sm-6 col-xs-12">
<a href="{{mainResult.hrefJson}}" class="btn-full-width btn btn-default">Download JSON <span class="glyphicon glyphicon-download"></span></a> <a href="{{mainResult.hrefJson}}" class="btn-full-width btn btn-default" data-test="download-json">
Download JSON <span class="glyphicon glyphicon-download"></span>
</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- ########### Functionality to be done ############# --> <div class="row">
<!-- List of other URLs --> <div class="col-md-12 col-sm-12 clearfix">
<!-- <div class="other-tasks well"> <div class="well">
<h4 class="crunch-top ruled-sm">Your other tracked URLs</h4> <h4 class="crunch-top">View results in browser</h4>
<p>No other URLs</p> <p class="crunch-bottom">pa11y uses HTML_CodeSniffer to find accessibility issues. <a href="http://squizlabs.github.io/HTML_CodeSniffer/">Use their bookmarklet</a> to view results on the page you are testing.</p>
</div>
</div>
<ul class="list-unstyled crunch-bottom"> </div>
<li><a href="empty-task">rowanmanning.com</a></li>
<li><a href="task">nature.com</a></li>
</ul>
</div> -->
<!-- ##################### End ######################## -->
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{#if mainResult.count.error}} {{#if mainResult.count.error}}
<div class="heading label-danger showing first" id="errors"> <div class="heading label-danger showing first" id="errors" data-test="task-errors">
<span data-role="expander" class="pull-right expander"> - </span> <span data-role="expander" class="pull-right expander"> - </span>
Errors ( {{mainResult.count.error}} ) Errors ( {{mainResult.count.error}} )
</div> </div>
@@ -48,6 +63,14 @@
<li> <li>
<p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p> <p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p>
<p>{{message}}</p> <p>{{message}}</p>
{{#unless readonly}}
{{#if ../../isTaskPage}}
<form action="{{../../../task.hrefIgnore}}" method="post">
<input type="hidden" name="rule" value="{{code}}"/>
<input type="submit" class="btn btn-sm" value="Ignore rule"/>
</form>
{{/if}}
{{/unless}}
</li> </li>
{{/mainResult.errors}} {{/mainResult.errors}}
</ul> </ul>
@@ -58,7 +81,7 @@
{{/if}} {{/if}}
{{#if mainResult.count.warning}} {{#if mainResult.count.warning}}
<div class="heading label-warning" id="warnings"> <div class="heading label-warning" id="warnings" data-test="task-warnings">
<span data-role="expander" class="pull-right expander"> + </span> <span data-role="expander" class="pull-right expander"> + </span>
Warnings ( {{mainResult.count.warning}} ) Warnings ( {{mainResult.count.warning}} )
</div> </div>
@@ -68,6 +91,14 @@
<li> <li>
<p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p> <p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p>
<p>{{message}}</p> <p>{{message}}</p>
{{#unless readonly}}
{{#if ../../isTaskPage}}
<form action="{{../../../task.hrefIgnore}}" method="post">
<input type="hidden" name="rule" value="{{code}}"/>
<input type="submit" class="btn btn-sm" value="Ignore rule"/>
</form>
{{/if}}
{{/unless}}
</li> </li>
{{/mainResult.warnings}} {{/mainResult.warnings}}
</ul> </ul>
@@ -79,7 +110,7 @@
{{/if}} {{/if}}
{{#if mainResult.count.notice}} {{#if mainResult.count.notice}}
<div class="heading label-info" id="notices"> <div class="heading label-info" id="notices" data-test="task-notices">
<span data-role="expander" class="pull-right expander"> + </span> <span data-role="expander" class="pull-right expander"> + </span>
Notices ( {{mainResult.count.notice}} ) Notices ( {{mainResult.count.notice}} )
</div> </div>
@@ -89,6 +120,14 @@
<li> <li>
<p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p> <p class="crunch rule-name">{{code}} <span class="badge">{{count}}</span></p>
<p>{{message}}</p> <p>{{message}}</p>
{{#unless readonly}}
{{#if ../../isTaskPage}}
<form action="{{../../../task.hrefIgnore}}" method="post">
<input type="hidden" name="rule" value="{{code}}"/>
<input type="submit" class="btn btn-sm" value="Ignore rule"/>
</form>
{{/if}}
{{/unless}}
</li> </li>
{{/mainResult.notices}} {{/mainResult.notices}}
</ul> </ul>
@@ -98,21 +137,29 @@
<p class="heading label-info" id="notices">Well done! You have 0 notices. <span class="glyphicon glyphicon-ok pull-right"></span></p> <p class="heading label-info" id="notices">Well done! You have 0 notices. <span class="glyphicon glyphicon-ok pull-right"></span></p>
{{/if}} {{/if}}
{{#if task.ignore.length}} {{#if mainResult.ignore.length}}
<div class="heading label-default"> <div class="heading label-default">
<span data-role="expander" class="pull-right expander"> + </span> <span data-role="expander" class="pull-right expander"> + </span>
Ignored Rules Ignored Rules ( {{mainResult.ignore.length}} )
</div> </div>
<div class="task-default tasks-list collapse clearfix"> <div class="task-default tasks-list collapse clearfix">
<ul class="list-unstyled"> <ul class="list-unstyled">
{{#task.ignore}} {{#mainResult.ignore}}
<li> <li>
<p class="crunch rule-name">{{name}}</p> <p class="crunch rule-name">{{name}}</p>
{{#if description}} {{#if description}}
<p>{{description}}</p> <p>{{description}}</p>
{{/if}} {{/if}}
{{#unless readonly}}
{{#if ../../isTaskPage}}
<form action="{{../../../task.hrefUnignore}}" method="post">
<input type="hidden" name="rule" value="{{name}}"/>
<input type="submit" class="btn btn-sm" value="Unignore rule"/>
</form>
{{/if}}
{{/unless}}
</li> </li>
{{/task.ignore}} {{/mainResult.ignore}}
</ul> </ul>
<a class="pull-right" href="#top" data-role="top">Back to top</a> <a class="pull-right" href="#top" data-role="top">Back to top</a>
</div> </div>

View File

@@ -1,4 +1,20 @@
<div class="col-md-12"> {{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div class="col-md-12 zfix">
<div class="ruled task-header"> <div class="ruled task-header">
<div class="row clearfix"> <div class="row clearfix">
<div class="col-md-9 col-sm-9"> <div class="col-md-9 col-sm-9">
@@ -7,7 +23,15 @@
</div> </div>
<div class="col-md-3 col-sm-3 text-right run-details"> <div class="col-md-3 col-sm-3 text-right run-details">
{{#unless readonly}} {{#unless readonly}}
<a href="{{task.hrefRun}}" class="btn btn-success">Run <span class="glyphicon glyphicon-play"></span></a> <div class="btn-group">
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">Options <span class="caret"></span></button>
<ul class="dropdown-menu pull-right" role="menu">
<li><a href="/{{task.id}}/edit">Edit this task</a></li>
<li><a href="/{{task.id}}/delete">Delete this task</a></li>
<li class="divider"></li>
<li><a href="{{task.hrefRun}}" data-test="run-task">Run pa11y</a></li>
</ul>
</div>
{{/unless}} {{/unless}}
{{#if mainResult}} {{#if mainResult}}
<div class="date">Last run : {{date-format mainResult.date format="DD MMM YYYY"}}</div> <div class="date">Last run : {{date-format mainResult.date format="DD MMM YYYY"}}</div>

View File

@@ -1,21 +1,46 @@
{{!
This file is part of pa11y-dashboard.
<ul class="list-unstyled clearfix crunch-bottom"> pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
<div data-control="task-list">
<div class="col-md-6 col-md-offset-3 filter-toggle no-js-hide text-center">
<label for="filter-input" class="filter-trigger" data-toggle="collapse" data-target="#filter-input">Filter<span class="glyphicon glyphicon-filter"></span>
</label>
<div id="filter-input" class="collapse">
<input class="form-control" id="task-filter" type="text" data-role="input" placeholder="Type filter term (name or standard)"/>
</div>
</div>
<ul class="list-unstyled clearfix crunch-bottom">
<li class="col-md-4 col-sm-6 task-card add-task"> <li class="col-md-4 col-sm-6 task-card add-task">
{{#if readonly}} {{#if readonly}}
{{! TODO PERRY: make this look disabled }}
<span class="well task-card-link crunch-bottom"> <span class="well task-card-link crunch-bottom">
<p class="h3 crunch">Add new URL</p> <p class="h3 crunch">Add new URL</p>
<p class="supersize-me crunch">+</p> <p class="supersize-me crunch">+</p>
</span> </span>
{{else}} {{else}}
<a class="well task-card-link crunch-bottom" data-role="add-task" href="/new"> <a class="well task-card-link crunch-bottom" data-role="add-task" href="/new" data-test="add-task">
<p class="h3 crunch">Add new URL</p> <p class="h3 crunch">Add new URL</p>
<p class="supersize-me crunch">+</p> <p class="supersize-me crunch">+</p>
</a> </a>
{{/if}} {{/if}}
</li> </li>
{{#each tasks}} {{#each tasks}}
<li class="col-md-4 col-sm-6 task-card"> <li class="col-md-4 col-sm-6 task-card" data-test="task" data-role="task" data-keywords="{{lowercase name}} {{lowercase standard}} {{simplify-url url}}">
<a class="well task-card-link crunch-bottom" title="Details for URL {{simplify-url url}}" href="{{href}}"> <a class="well task-card-link crunch-bottom" title="Details for URL {{simplify-url url}}" href="{{href}}">
<p class="h3">{{name}}</p> <p class="h3">{{name}}</p>
<p class="h5">({{standard}})</p> <p class="h5">({{standard}})</p>
@@ -33,8 +58,18 @@
{{/if}} {{/if}}
</a> </a>
{{#unless ../readonly}} {{#unless ../readonly}}
<a title="Delete this URL" class="delete-button" href="{{hrefDelete}}"><span class="sr-only">Delete </span><span class="glyphicon glyphicon-remove"></span></a> <div class="btn-group options-button text-right">
<button type="button" class="btn btn-info btn-xs dropdown-toggle" data-toggle="dropdown"><span class="sr-only">Options</span><span class="glyphicon glyphicon-cog"></span></button>
<ul class="dropdown-menu pull-right" role="menu">
<li><a href="{{href}}/edit">Edit this task</a></li>
<li><a href="{{href}}/delete">Delete this task</a></li>
<li class="divider"></li>
<li><a href="{{href}}/run" data-test="run-task">Run pa11y</a></li>
</ul>
</div>
{{/unless}} {{/unless}}
</li> </li>
{{/each}} {{/each}}
</ul> </ul>
</div>

40
view/presenter/ignore.js Normal file
View File

@@ -0,0 +1,40 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict';
var standardsArray = require('../../data/standards')();
var rules = createStandardDescriptionMap(standardsArray);
module.exports = presentIgnoreRules;
function presentIgnoreRules (ignore) {
return ignore.map(function (name) {
return {
name: name,
description: rules[name]
};
});
}
function createStandardDescriptionMap (standards) {
var map = {};
standards.forEach(function (standard) {
standard.rules.forEach(function (rule) {
map[rule.name] = rule.description;
});
});
return map;
}

View File

@@ -1,3 +1,18 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var _ = require('underscore'); var _ = require('underscore');

View File

@@ -1,6 +1,22 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var _ = require('underscore'); var _ = require('underscore');
var presentIgnoreRules = require('./ignore');
module.exports = presentResult; module.exports = presentResult;
@@ -14,6 +30,9 @@ function presentResult (result) {
// Parse date // Parse date
result.date = new Date(result.date); result.date = new Date(result.date);
// Enhance the ignored rules
result.ignore = presentIgnoreRules(result.ignore);
// Split out message types // Split out message types
if (result.results) { if (result.results) {
var groupedByType = _.groupBy(result.results, 'type'); var groupedByType = _.groupBy(result.results, 'type');

View File

@@ -1,9 +1,23 @@
// This file is part of pa11y-dashboard.
//
// pa11y-dashboard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pa11y-dashboard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
'use strict'; 'use strict';
var _ = require('underscore'); var _ = require('underscore');
var presentIgnoreRules = require('./ignore');
var presentResult = require('./result'); var presentResult = require('./result');
var standardsArray = require('../../data/standards')();
var rules = createStandardDescriptionMap(standardsArray);
module.exports = presentTask; module.exports = presentTask;
@@ -14,14 +28,12 @@ function presentTask (task) {
task.hrefDelete = '/' + task.id + '/delete'; task.hrefDelete = '/' + task.id + '/delete';
task.hrefRun = '/' + task.id + '/run'; task.hrefRun = '/' + task.id + '/run';
task.hrefJson = '/' + task.id + '.json'; task.hrefJson = '/' + task.id + '.json';
task.hrefEdit = '/' + task.id + '/edit';
task.hrefIgnore = '/' + task.id + '/ignore';
task.hrefUnignore = '/' + task.id + '/unignore';
// Enhance the ignored rules // Enhance the ignored rules
task.ignore = task.ignore.map(function (name) { task.ignore = presentIgnoreRules(task.ignore);
return {
name: name,
description: rules[name]
};
});
// Present the last result if present // Present the last result if present
if (task.last_result) { if (task.last_result) {
@@ -31,13 +43,3 @@ function presentTask (task) {
return task; return task;
} }
function createStandardDescriptionMap (standards) {
var map = {};
standards.forEach(function (standard) {
standard.rules.forEach(function (rule) {
map[rule.name] = rule.description;
});
});
return map;
}

View File

@@ -1,3 +1,19 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}} {{#content "title"}}
{{task.name}} - {{simplify-url task.url}} ({{task.standard}}) - {{date-format mainResult.date format="DD MMM YYYY"}} {{task.name}} - {{simplify-url task.url}} ({{task.standard}}) - {{date-format mainResult.date format="DD MMM YYYY"}}

View File

@@ -1,9 +1,25 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}} {{#content "title"}}
Delete {{task.url}} ({{task.standard}}) Delete {{task.url}} ({{task.standard}})
{{/content}} {{/content}}
<form class="col-md-12" action="{{task.hrefDelete}}" method="post"> <form class="col-md-12" action="{{task.hrefDelete}}" method="post" data-test="delete-url-form">
<div class="legend"> <div class="legend">
<legend>Delete URL ({{simplify-url task.url}})</legend> <legend>Delete URL ({{simplify-url task.url}})</legend>
</div> </div>

103
view/task/edit.html Normal file
View File

@@ -0,0 +1,103 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}}
Edit URL
{{/content}}
{{#edited}}
<div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>Success!</strong>
<p>Your changes have been saved.</p>
</div>
</div>
{{/edited}}
<form role="form" class="col-md-12" action="/{{task.id}}/edit" method="post" data-test="edit-url-form">
<div class="legend">
<h1 class="h2 crunch-top">Edit URL</h1>
</div>
{{#error}}
<div class="col-md-12 clearfix" data-test="error">
<div class="row">
<div class="alert alert-danger">
<strong>Oh my gosh!</strong>
<p>{{.}}</p>
</div>
</div>
</div>
{{/error}}
<div class="form-group clearfix">
<div class="row">
<div class="col-md-8 col-sm-8 col-xs-10">
<label class="control-label" for="new-task-name">Name</label>
<input class="form-control" id="new-task-name" type="text" placeholder="E.g. My Home Page" name="name" value="{{task.name}}"/>
</div>
</div>
</div>
<div class="form-group clearfix">
<div class="row">
<div class="col-md-8 col-sm-8 col-xs-10">
<label class="control-label" for="new-task-url">URL</label>
<input class="form-control" id="new-task-url" type="url" placeholder="E.g. http://mysite.com/" name="url" value="{{task.url}}" disabled/>
</div>
</div>
</div>
<div class="form-group clearfix">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-6">
<label class="control-label" for="new-task-standard">Standard</label>
<select data-role="new-task-select" class="form-control" id="new-task-standard" name="standard" disabled>
{{#standards}}
<option {{#selected}}selected{{/selected}}>{{title}}</option>
{{/standards}}
</select>
</div>
</div>
</div>
<p class="control-label"><b>Ignore these rules</b> <a target="_blank" href="https://github.com/nature/pa11y/wiki/HTML-CodeSniffer-Rules">(full list of rules here)</a></p>
<div class="standards-lists">
{{#standards}}
<div data-role="standards-list" data-attr="{{title}}" class="form-group">
<p class="control-label rules-list-title ruled"><b>{{title}} Rules</b></p>
<ul class="list-unstyled">
{{#rules}}
<li>
<input class="pull-left" id="{{name}}" type="checkbox" name="ignore[]" value="{{name}}" {{#ignored}}checked{{/ignored}}/>
<label for="{{name}}" title="{{description}}" data-role="rules-tooltip" class="checkbox">
{{name}}
</label>
</li>
{{/rules}}
</ul>
</div>
{{/standards}}
</div>
<button type="submit" class="btn btn-success">Save changes <span class="glyphicon glyphicon-save"></span></button>
<a href="/{{task.id}}/edit" class="btn btn-primary">Undo <span class="glyphicon glyphicon-refresh"></span></a>
</form>

View File

@@ -1,10 +1,26 @@
{{!
This file is part of pa11y-dashboard.
pa11y-dashboard is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pa11y-dashboard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pa11y-dashboard. If not, see <http://www.gnu.org/licenses/>.
}}
{{#content "title"}} {{#content "title"}}
{{task.name}} - {{simplify-url task.url}} ({{task.standard}}) {{task.name}} - {{simplify-url task.url}} ({{task.standard}})
{{/content}} {{/content}}
{{#added}} {{#added}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button> <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>Whoop whoop!</strong> <strong>Whoop whoop!</strong>
@@ -14,7 +30,7 @@
{{/added}} {{/added}}
{{#running}} {{#running}}
<div class="col-md-12 clearfix"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button> <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>New results incoming!</strong> <strong>New results incoming!</strong>
@@ -26,6 +42,32 @@
</div> </div>
{{/running}} {{/running}}
{{#ruleIgnored}}
<div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>Rule ignored!</strong>
<p>
You've ignored an accessibility rule for this URL.
<a href="{{task.hrefRun}}">Click here to generate results with the ignored rule excluded</a>
</p>
</div>
</div>
{{/ruleIgnored}}
{{#ruleUnignored}}
<div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
<strong>Rule unignored!</strong>
<p>
You've removed an ignored accessibility rule for this URL.
<a href="{{task.hrefRun}}">Click here to generate results with the ignored rule included again</a>
</p>
</div>
</div>
{{/ruleUnignored}}
{{> task-header}} {{> task-header}}
{{#if results}} {{#if results}}
@@ -41,7 +83,7 @@
{{#if mainResult}} {{#if mainResult}}
{{> result}} {{> result}}
{{else}} {{else}}
<div class="col-md-12"> <div class="col-md-12" data-test="alert">
<div class="alert alert-info"> <div class="alert alert-info">
<h4>There are no results to show</h4> <h4>There are no results to show</h4>
<p>pa11y has not been run against this URL yet so there are no results to show.</p> <p>pa11y has not been run against this URL yet so there are no results to show.</p>