Compare commits

...

10 Commits

Author SHA1 Message Date
dependabot[bot]
ee6c79f70a Bump minimatch and mocha
Bumps [minimatch](https://github.com/isaacs/minimatch) to 3.1.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `minimatch` from 3.0.4 to 3.1.2
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

Updates `mocha` from 7.2.0 to 10.2.0
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v7.2.0...v10.2.0)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-12 16:08:02 +00:00
Danyal Aytekin
e55cae4786 In workflow, update default branch to main, use ubuntu-20.04 (#315)
* Update default branch name to `main`

* Use `ubuntu-20.04` for build, until this project upgrades to `pa11y-webservice@5`
2023-11-12 15:52:09 +00:00
Sangita Mane
5202f59008 A11y fixes for pa11y dashboard pages. (#306)
* First draft of a11y fixes.

* Amended results title

* Amended results title (again)

* Back to top keyboard operation

Removed the 'data-role="top"' attribute, which implemented a cool animation to scroll to top but prevented the default behaviour, resulting in the keyboard focus not going back to top.

* Options Button

Fix to have a working options button, but using the mouse only. This is not a good solution because it cannot be operated via the keyboard.

* Fixed options menu css.

* Results view layout changes

* Undoing layout changes

* Graph layout fixes.

* Skip Rules Link

Added a link to skip the list of rules, which can get very long and annoying for any keyboard user not interested in selecting a rule. Most probably, implementing a collapsible list of rules would be a better solution here.

Co-authored-by: Carlos Muncharaz <carlos@muncharaz.eu>
2022-10-11 14:17:43 +02:00
Jose Bolos
b9b049ec2b Address all eslint warnings
Address all eslint warnings that were still present by:

* Extracting code to a new function in order to reduce complexity
* Renamed error variables and use shorthand notation for objects
* Disabling eslint warnings where addressing the issue would require too much refactoring
2022-04-11 17:27:15 +02:00
Jose Bolos
0e7849dd07 Add issue template 2022-04-08 14:29:44 +01:00
Jose Bolos
3b76433cf3 Version 4.2.0 2022-03-30 17:19:08 +01:00
Jose Bolos
f3462f0c1e Bump webservice, deps, and linter configuration
* Bump webservice to require the latest 4.0.1 version
* Bump other dependencies
* Update linter conf to v2 which avoids the "Unsupported engine" warning when using node 12
* Keep all other devdependencies as they are so they stay consistent with the other repos
2022-03-30 18:16:25 +02:00
Jose Bolos
9dbee59746 Add request logging using morgan
This commit adds request logging to the app using morgan.

Every request will now be logged not one but twice: one when the request is received, and a second time when the response is sent.

The response logging also prints out the time elapsed in processing the request, which will be useful to debug performance issues (calls to the dashboard home are currently taking 4 - 15s on a populated database).

The new code uses a tiny middleware that uses nanoid to generate a random request id that can be used to match requests in the logs.

This logging will help us determine which requests are successful, which requests are slow, and establish what requests may have contributed to causing an application crash, making future debugging easier.
2022-03-08 11:19:15 +01:00
Jose Bolos
321d7bb6ba Split initApp in different functions
This makes the function easier to understand and fixes eslint complaints
about the function having too many statements.
2022-03-07 15:55:34 +01:00
Jose Bolos
4fd73bcf2f Make .editorconfig consistent between repos 2022-03-03 13:59:11 +00:00
31 changed files with 8754 additions and 190 deletions

View File

@@ -5,9 +5,19 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
insert_final_newline = true indent_size = 4
indent_style = tab indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.md] [*.md]
indent_style = spaces
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.yml]
indent_style = space
indent_size = 2
[package.json]
indent_style = space
indent_size = 2

20
.github/issue_template.md vendored Normal file
View File

@@ -0,0 +1,20 @@
**This repository's issues are reserved for feature requests, bug reports, and other issues with Pa11y Dashboard itself.**
If you need help using Pa11y Dashboard, we recommend using [Stack Overflow](https://stackoverflow.com/questions/tagged/pa11y).
For a bug report, please use the template below. To keep the backlog clean and actionable, issues may be immediately closed if they do not follow one this template.
---
## Expected behaviour
## Actual behaviour
## Steps to reproduce
## Environment
_Please specify the versions of Pa11y Dashboard, MongoDB, and Node.js that can be sued to reproduce this issue._

View File

@@ -1,19 +1,14 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests.
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Build and lint name: Build and lint
on: on:
push: push:
branches: # Run actions when code is committed to these branches branches:
- master - main
pull_request: pull_request:
branches: # Run actions when a PR is pushed based on one of these branches
- master
jobs: jobs:
checkout_and_test: checkout_and_test:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
include: include:

View File

@@ -1,5 +1,10 @@
# Changelog # Changelog
## 4.2.0 (2022-03-30)
* Add request logging for easier debugging
* Dependencies update
## 4.1.0 (2021-11-26) ## 4.1.0 (2021-11-26)
* Add support for new WCAG 2.1 rules and remove all references to Section 508. * Add support for new WCAG 2.1 rules and remove all references to Section 508.

78
app.js
View File

@@ -20,6 +20,8 @@ const createClient = require('pa11y-webservice-client-node');
const EventEmitter = require('events').EventEmitter; const EventEmitter = require('events').EventEmitter;
const express = require('express'); const express = require('express');
const hbs = require('express-hbs'); const hbs = require('express-hbs');
const morgan = require('morgan');
const {nanoid} = require('nanoid');
const http = require('http'); const http = require('http');
const pkg = require('./package.json'); const pkg = require('./package.json');
@@ -35,14 +37,57 @@ function initApp(config, callback) {
} }
const app = new EventEmitter(); const 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(webserviceUrl); app.webservice = createClient(webserviceUrl);
loadMiddleware(app);
// View engine
loadViewEngine(app, config);
// Load routes
loadRoutes(app, config);
// Error handling
loadErrorHandling(app, config, callback);
}
// Get default configurations
function defaultConfig(config) {
if (typeof config.noindex !== 'boolean') {
config.noindex = true;
}
if (typeof config.readonly !== 'boolean') {
config.readonly = false;
}
return config;
}
function loadMiddleware(app) {
// Compression // Compression
app.express.use(compression()); app.express.use(compression());
// Adds an ID to every request, used later for logging
app.express.use(addRequestId);
// Logging middleware
morgan.token('id', request => {
return request.id;
});
// Log the start of all HTTP requests
const startLog = '[:date[iso] #:id] Started :method :url for :remote-addr';
// Immediate: true is required to log the request
// before the response happens
app.express.use(morgan(startLog, {immediate: true}));
// Log the end of all HTTP requests
const endLog = '[:date[iso] #:id] Completed :status :res[content-length] in :response-time ms';
app.express.use(morgan(endLog));
// Public files // Public files
app.express.use(express.static(`${__dirname}/public`, { app.express.use(express.static(`${__dirname}/public`, {
maxAge: (process.env.NODE_ENV === 'production' ? 604800000 : 0) maxAge: (process.env.NODE_ENV === 'production' ? 604800000 : 0)
@@ -53,8 +98,9 @@ function initApp(config, callback) {
app.express.use(bodyParser.urlencoded({ app.express.use(bodyParser.urlencoded({
extended: true extended: true
})); }));
}
// View engine function loadViewEngine(app, config) {
app.express.engine('html', hbs.express4({ app.express.engine('html', hbs.express4({
extname: '.html', extname: '.html',
contentHelperName: 'content', contentHelperName: 'content',
@@ -89,10 +135,16 @@ function initApp(config, callback) {
response.locals.host = request.hostname; response.locals.host = request.hostname;
next(); next();
}); });
}
// Load routes function loadRoutes(app, config) {
// Because there's some overlap between the different routes,
// they have to be loaded in a specific order in order to avoid
// passing mongo the wrong id which would result in
// "ObjectID generation failed." errors (e.g. #277)
require('./route/index')(app); require('./route/index')(app);
require('./route/result/download')(app); require('./route/result/download')(app);
if (!config.readonly) { if (!config.readonly) {
require('./route/new')(app); require('./route/new')(app);
require('./route/task/delete')(app); require('./route/task/delete')(app);
@@ -101,12 +153,14 @@ function initApp(config, callback) {
require('./route/task/ignore')(app); require('./route/task/ignore')(app);
require('./route/task/unignore')(app); require('./route/task/unignore')(app);
} }
// Needs to be loaded after `/route/new` // Needs to be loaded after `/route/new`
require('./route/task/index')(app); require('./route/task/index')(app);
// Needs to be loaded after `/route/task/edit` // Needs to be loaded after `/route/task/edit`
require('./route/result/index')(app); require('./route/result/index')(app);
}
// Error handling function loadErrorHandling(app, config, callback) {
app.express.get('*', (request, response) => { app.express.get('*', (request, response) => {
response.status(404); response.status(404);
response.render('404'); response.render('404');
@@ -129,16 +183,14 @@ function initApp(config, callback) {
app.address = `http://${address.address}:${address.port}`; app.address = `http://${address.address}:${address.port}`;
callback(error, app); callback(error, app);
}); });
} }
// Get default configurations // Express middleware
function defaultConfig(config) { function addRequestId(request, response, next) {
if (typeof config.noindex !== 'boolean') { // Create a random request (nano)id, 10 characters long
config.noindex = true; // Nano ids are [0-9A-Za-z_-] so chance of collision is 1 in 64^10
} // If a site has so much traffic that this chance is too high
if (typeof config.readonly !== 'boolean') { // we probably have worse things to worry about
config.readonly = false; request.id = nanoid(10);
} next();
return config;
} }

View File

@@ -805,7 +805,7 @@ function getStandards() {
description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 4.5:1.' description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 4.5:1.'
}, },
{ {
name: 'WCAG2AA.Principle1.Guideline1_4.1_4_3.G145 ', name: 'WCAG2AA.Principle1.Guideline1_4.1_4_3.G1451',
description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 3:1.' description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 3:1.'
}, },
{ {
@@ -1430,11 +1430,11 @@ function getStandards() {
description: 'This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of /{value/}. Recommendation: /{colour recommendations/}.' description: 'This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of /{value/}. Recommendation: /{colour recommendations/}.'
}, },
{ {
name: 'WCAG2AAA.Principle1.Guideline1_4.1_4_6.G17 ', name: 'WCAG2AAA.Principle1.Guideline1_4.1_4_6.G17-1',
description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 7:1.' description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 7:1.'
}, },
{ {
name: 'WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18 ', name: 'WCAG2AAA.Principle1.Guideline1_4.1_4_6.G18-1',
description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 4.5:1.' description: 'This element\'s text is placed on a background image. Ensure the contrast ratio between the text and all covered parts of the image are at least 4.5:1.'
}, },
{ {

View File

@@ -33,8 +33,8 @@ require('./app')(config, (error, app) => {
console.log(kleur.grey('mode: %s'), process.env.NODE_ENV); console.log(kleur.grey('mode: %s'), process.env.NODE_ENV);
console.log(kleur.grey('uri: %s'), app.address); console.log(kleur.grey('uri: %s'), app.address);
app.on('route-error', error => { app.on('route-error', routeError => {
const stack = (error.stack ? error.stack.split('\n') : [error.message]); const stack = (routeError.stack ? routeError.stack.split('\n') : [routeError.message]);
const msg = kleur.red(stack.shift()); const msg = kleur.red(stack.shift());
console.error(''); console.error('');
console.error(msg); console.error(msg);
@@ -43,9 +43,9 @@ require('./app')(config, (error, app) => {
// Start the webservice if required // Start the webservice if required
if (typeof config.webservice === 'object') { if (typeof config.webservice === 'object') {
require('pa11y-webservice')(config.webservice, (error, webservice) => { require('pa11y-webservice')(config.webservice, (webserviceError, webservice) => {
if (error) { if (webserviceError) {
console.error(error.stack); console.error(webserviceError.stack);
process.exit(1); process.exit(1);
} }

8438
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "pa11y-dashboard", "name": "pa11y-dashboard",
"version": "4.1.0", "version": "4.2.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",
"keywords": [ "keywords": [
@@ -24,24 +24,26 @@
"node": ">=12 <16" "node": ">=12 <16"
}, },
"dependencies": { "dependencies": {
"body-parser": "~1.19.0", "body-parser": "~1.19.2",
"compression": "~1.7.4", "compression": "~1.7.4",
"express": "~4.17.1", "express": "~4.17.3",
"express-hbs": "~2.4.0", "express-hbs": "~2.4.0",
"http-headers": "~3.0.2", "http-headers": "~3.0.2",
"kleur": "~4.1.4", "kleur": "~4.1.4",
"moment": "~2.29.1", "moment": "~2.29.1",
"pa11y-webservice": "~4.0.0", "morgan": "~1.10.0",
"nanoid": "~3.3.2",
"pa11y-webservice": "~4.0.1",
"pa11y-webservice-client-node": "~3.0.0", "pa11y-webservice-client-node": "~3.0.0",
"underscore": "~1.13.1" "underscore": "~1.13.2"
}, },
"devDependencies": { "devDependencies": {
"bower": "^1.8.13", "bower": "^1.8.13",
"cheerio": "^1.0.0-rc.10", "cheerio": "^1.0.0-rc.10",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"less": "^3.11.1", "less": "^3.11.1",
"mocha": "^8.4.0", "mocha": "^10.2.0",
"pa11y-lint-config": "^1.2.1", "pa11y-lint-config": "^2.0.0",
"proclaim": "^3.6.0", "proclaim": "^3.6.0",
"request": "^2.88.2", "request": "^2.88.2",
"uglify-js": "^3.11.0" "uglify-js": "^3.11.0"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -43,9 +43,9 @@
</ul> </ul>
</div> </div>
</div> </div>
<div class="col-md-9" role="main"> <main class="col-md-9" role="main">
{{ content }} {{ content }}
</div> </main>
</div> </div>
</div> </div>

View File

@@ -68,10 +68,12 @@
function next() { function next() {
$active $active
.removeClass('active') .removeClass('active')
.attr('aria-selected', false)
.find('> .dropdown-menu > .active') .find('> .dropdown-menu > .active')
.removeClass('active') .removeClass('active')
element.addClass('active') element.addClass('active')
element.attr('aria-selected', true)
if (transition) { if (transition) {
element[0].offsetWidth // reflow for transition element[0].offsetWidth // reflow for transition

View File

@@ -32,7 +32,7 @@ $(function () {
$.support.transition = false $.support.transition = false
var alertHTML = '<div class="alert-message warning fade in">' var alertHTML = '<div class="alert-message warning fade in">'
+ '<a class="close" href="#" data-dismiss="alert">×</a>' + '<a class="close" href="#" data-dismiss="alert" aria-label="Close">×</a>'
+ '<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>' + '<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>'
+ '</div>' + '</div>'
, alert = $(alertHTML).appendTo('#qunit-fixture').alert() , alert = $(alertHTML).appendTo('#qunit-fixture').alert()

View File

@@ -95,6 +95,11 @@
li a { li a {
text-indent: -20px; text-indent: -20px;
} }
ul.options-menu {
list-style: none;
padding: 5px 0;
margin: 2px 10px 0 0;
}
} }
.dropdown-toggle { .dropdown-toggle {
@@ -262,6 +267,7 @@
} }
/* Task details page*/ /* Task details page*/
.task-header { .task-header {
margin-bottom: 30px; margin-bottom: 30px;
@@ -502,6 +508,10 @@ ul.date-links {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.dates-list > li:first-child a {
font-weight: bold;
font-size: 16px;
}
.dates-list a { .dates-list a {
color: #fff; color: #fff;
@@ -709,6 +719,16 @@ ul.date-links {
} }
} }
/* Edit task page */
#skipRules {
position: absolute;
left: -999px;
}
#skipRules:focus {
position: static;
}
/* inline link list */ /* inline link list */
.inline-list { .inline-list {
@@ -760,3 +780,7 @@ ul.date-links {
opacity: 1; opacity: 1;
}; };
} }
section {
margin: 1em 0;
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable complexity */
// This file is part of Pa11y Dashboard. // This file is part of Pa11y Dashboard.
// //
// Pa11y Dashboard is free software: you can redistribute it and/or modify // Pa11y Dashboard is free software: you can redistribute it and/or modify
@@ -30,42 +31,21 @@ function route(app) {
return standard; return standard;
}); });
response.render('new', { response.render('new', {
standards: standards, standards,
isNewTaskPage: true isNewTaskPage: true
}); });
}); });
app.express.post('/new', (request, response) => { app.express.post('/new', (request, response) => {
let parsedActions; const parsedActions = parseActions(request.body.actions);
if (request.body.actions) {
parsedActions = request.body.actions.split(/[\r\n]+/)
.map(action => {
return action.trim();
})
.filter(action => {
return Boolean(action);
});
}
let parsedHeaders; let parsedHeaders;
if (request.body.headers) { if (request.body.headers) {
parsedHeaders = httpHeaders(request.body.headers, true); parsedHeaders = httpHeaders(request.body.headers, true);
} }
const newTask = { const newTask = createNewTask(request, parsedActions, parsedHeaders);
name: request.body.name,
url: request.body.url,
standard: request.body.standard,
ignore: request.body.ignore || [],
timeout: request.body.timeout || undefined,
wait: request.body.wait || undefined,
actions: parsedActions,
username: request.body.username || undefined,
password: request.body.password || undefined,
headers: parsedHeaders,
hideElements: request.body.hideElements || undefined
};
app.webservice.tasks.create(newTask, (error, task) => { app.webservice.tasks.create(newTask, (error, task) => {
if (error) { if (error) {
@@ -84,8 +64,8 @@ function route(app) {
newTask.actions = request.body.actions; newTask.actions = request.body.actions;
newTask.headers = request.body.headers; newTask.headers = request.body.headers;
return response.render('new', { return response.render('new', {
error: error, error,
standards: standards, standards,
task: newTask task: newTask
}); });
} }
@@ -94,3 +74,32 @@ function route(app) {
}); });
} }
function parseActions(actions) {
if (actions) {
return actions.split(/[\r\n]+/)
.map(action => {
return action.trim();
})
.filter(action => {
return Boolean(action);
});
}
}
/* eslint-disable complexity */
function createNewTask(request, actions, headers) {
return {
name: request.body.name,
url: request.body.url,
standard: request.body.standard,
ignore: request.body.ignore || [],
timeout: request.body.timeout || undefined,
wait: request.body.wait || undefined,
actions,
username: request.body.username || undefined,
password: request.body.password || undefined,
headers,
hideElements: request.body.hideElements || undefined
};
}

View File

@@ -29,8 +29,8 @@ function route(app) {
app.webservice app.webservice
.task(request.params.id) .task(request.params.id)
.result(request.params.rid) .result(request.params.rid)
.get({full: true}, (error, result) => { .get({full: true}, (webserviceError, result) => {
if (error) { if (webserviceError) {
return next('route'); return next('route');
} }
response.locals.task = task; response.locals.task = task;

View File

@@ -30,8 +30,8 @@ function route(app) {
app.webservice app.webservice
.task(request.params.id) .task(request.params.id)
.result(request.params.rid) .result(request.params.rid)
.get({full: true}, (error, result) => { .get({full: true}, (webserviceError, result) => {
if (error) { if (webserviceError) {
return next(); return next();
} }
response.render('result', { response.render('result', {

View File

@@ -43,13 +43,15 @@ function route(app) {
task.actions = (task.actions ? task.actions.join('\n') : ''); task.actions = (task.actions ? task.actions.join('\n') : '');
response.render('task/edit', { response.render('task/edit', {
edited: (typeof request.query.edited !== 'undefined'), edited: (typeof request.query.edited !== 'undefined'),
standards: standards, standards,
task: presentTask(task), task: presentTask(task),
isTaskSubPage: true isTaskSubPage: true
}); });
}); });
}); });
/* eslint-disable complexity */
/* eslint-disable max-statements */
app.express.post('/:id/edit', (request, response, next) => { app.express.post('/:id/edit', (request, response, next) => {
app.webservice.task(request.params.id).get({}, (error, task) => { app.webservice.task(request.params.id).get({}, (error, task) => {
if (error) { if (error) {
@@ -57,9 +59,11 @@ function route(app) {
} }
const originalActions = request.body.actions; const originalActions = request.body.actions;
const originalHeaders = request.body.headers; const originalHeaders = request.body.headers;
request.body.ignore = request.body.ignore || []; request.body.ignore = request.body.ignore || [];
request.body.timeout = request.body.timeout || undefined; request.body.timeout = request.body.timeout || undefined;
request.body.wait = request.body.wait || undefined; request.body.wait = request.body.wait || undefined;
if (request.body.actions) { if (request.body.actions) {
request.body.actions = request.body.actions.split(/[\r\n]+/) request.body.actions = request.body.actions.split(/[\r\n]+/)
.map(action => { .map(action => {
@@ -69,15 +73,18 @@ function route(app) {
return Boolean(action); return Boolean(action);
}); });
} }
if (!request.body.actions) { if (!request.body.actions) {
request.body.actions = []; request.body.actions = [];
} }
request.body.username = request.body.username || undefined; request.body.username = request.body.username || undefined;
request.body.password = request.body.password || undefined; request.body.password = request.body.password || undefined;
request.body.hideElements = request.body.hideElements || undefined; request.body.hideElements = request.body.hideElements || undefined;
request.body.headers = httpHeaders(request.body.headers || '', true); request.body.headers = httpHeaders(request.body.headers || '', true);
app.webservice.task(request.params.id).edit(request.body, error => {
if (error) { app.webservice.task(request.params.id).edit(request.body, webserviceError => {
if (webserviceError) {
task.name = request.body.name; task.name = request.body.name;
task.ignore = request.body.ignore; task.ignore = request.body.ignore;
task.timeout = request.body.timeout; task.timeout = request.body.timeout;
@@ -100,9 +107,9 @@ function route(app) {
return standard; return standard;
}); });
return response.render('task/edit', { return response.render('task/edit', {
error: error, webserviceError,
standards: standards, standards,
task: task, task,
isTaskSubPage: true isTaskSubPage: true
}); });
} }

View File

@@ -28,9 +28,9 @@ function route(app) {
if (error) { if (error) {
return next(); return next();
} }
app.webservice.task(request.params.id).results({}, (error, results) => { app.webservice.task(request.params.id).results({}, (webserviceError, results) => {
if (error) { if (webserviceError) {
return next(error); return next(webserviceError);
} }
const presentedResults = presentResultList(results.map(presentResult)); const presentedResults = presentResultList(results.map(presentResult));
response.render('task', { response.render('task', {

View File

@@ -47,19 +47,17 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{> breadcrumb}} {{> breadcrumb}}
<div class="container"> <main class="container" >
{{#if readonly}} {{#if readonly}}
<div class="row readonly-mode"> <div class="row readonly-mode">
{{else}} {{else}}
<div class="row"> <div class="row">
{{/if}} {{/if}}
<section> <div class="section">
<div class="section" role="main">
{{{body}}} {{{body}}}
</div> </div>
</section>
</div>
</div> </div>
</main>
{{> page-footer}} {{> page-footer}}

View File

@@ -78,8 +78,8 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-4 col-xs-6"> <div class="col-md-4 col-sm-4 col-xs-6">
<label class="control-label" for="new-task-wait">Wait (milliseconds)</label> <label class="control-label" for="new-task-wait">Wait (milliseconds)</label>
<input class="form-control" id="new-task-wait" type="text" placeholder="E.g. 3000" name="wait" value="{{task.wait}}"/> <input class="form-control" id="new-task-wait" type="text" placeholder="E.g. 3000" name="wait" value="{{task.wait}}" aria-describedby="int3"/>
<em>(Note: default wait time is 0ms)</em> <em id="int3">(Note: default wait time is 0ms)</em>
</div> </div>
</div> </div>
</div> </div>
@@ -110,7 +110,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-4 col-xs-6"> <div class="col-md-4 col-sm-4 col-xs-6">
<label class="control-label" for="new-task-password">Password</label> <label class="control-label" for="new-task-password">Password</label>
<input class="form-control" id="new-task-password" type="text" name="password" value="{{task.password}}"/> <em>(Note: this will be stored and displayed in plain-text - only suitable for use in a secure environment)</em> <input class="form-control" id="new-task-password" type="text" name="password" value="{{task.password}}" aria-describedby="pwd"/> <span id="pwd"><em>(Note: this will be stored and displayed in plain-text - only suitable for use in a secure environment)</em></span>
</div> </div>
</div> </div>
</div> </div>
@@ -119,8 +119,8 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-4 col-xs-6"> <div class="col-md-4 col-sm-4 col-xs-6">
<label class="control-label" for="new-task-headers">HTTP Headers</label> <label class="control-label" for="new-task-headers">HTTP Headers</label>
<textarea class="form-control" id="new-task-headers" name="headers" placeholder="Cookie: foo=bar">{{task.headers}}</textarea> <textarea class="form-control" id="new-task-headers" name="headers" placeholder="Cookie: foo=bar" aria-describedby="int1">{{task.headers}}</textarea>
<em>(As key/value pairs, separated by newlines/colons)</em> <em id="int1">(As key/value pairs, separated by newlines/colons)</em>
</div> </div>
</div> </div>
</div> </div>
@@ -129,7 +129,8 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-4 col-xs-6"> <div class="col-md-4 col-sm-4 col-xs-6">
<label class="control-label" for="new-task-hide-elements">Hide Elements</label> <label class="control-label" for="new-task-hide-elements">Hide Elements</label>
<input class="form-control" id="new-task-hide-elements" type="text" name="hideElements" value="{{task.hideElements}}" placeholder=".advert, #modal, div[aria-role=presentation]"/> <em>(CSS selector)</em> <input class="form-control" id="new-task-hide-elements" type="text" name="hideElements" value="{{task.hideElements}}" placeholder=".advert, #modal, div[aria-role=presentation]" aria-describedby="int2"/>
<em id="int2">(CSS selector)</em>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -15,9 +15,10 @@ You should have received a copy of the GNU General Public License
along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>. along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
}} }}
{{#unless isHomePage}} {{#unless isHomePage}}
<div class="container"> <nav class="container" aria-labelledby="breadcrumb">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2 id="breadcrumb" class="sr-only">Breadcrumb Navigation</h2>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="/">Dashboard</a></li> <li><a href="/">Dashboard</a></li>
{{#if isNewTaskPage}} {{#if isNewTaskPage}}
@@ -36,5 +37,5 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</ol> </ol>
</div> </div>
</div> </div>
</div> </nav>
{{/unless}} {{/unless}}

View File

@@ -18,9 +18,8 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="graph-container graph-spacer ruled clearfix"> <div class="graph-container graph-spacer ruled clearfix">
<div class="row"> <div class="row">
<div class="col-md-3 col-sm-4 col-xs-3"> <div class="col-md-3 col-sm-4 col-xs-3">
<span class="btn btn-sm btn-default btn-full-width btn_action_export">Export graph</span> <button class="btn btn-sm btn-default btn-full-width btn_action_export" type="button">Export graph</button>
</div> </div>
<div class="col-md-5 col-sm-6 col-xs-9 pull-right"> <div class="col-md-5 col-sm-6 col-xs-9 pull-right">
<ul class="list-unstyled floated-list series-checkboxes clearfix" data-role="series-checkboxes"></ul> <ul class="list-unstyled floated-list series-checkboxes clearfix" data-role="series-checkboxes"></ul>
</div> </div>
@@ -59,10 +58,10 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
</div> </div>
<button data-role='zoom-reset' class="btn btn-xs btn-primary pull-right btn-reset hidden">Reset Zoom <i class="glyphicon glyphicon-zoom-out"></i></button> <button data-role='zoom-reset' class="btn btn-xs btn-primary pull-right btn-reset hidden">Reset Zoom <i class="glyphicon glyphicon-zoom-out"></i></button>
</div>
</div>
<div class="col-md-12 hidden"> </div>
<div class="col-md-12 hidden">
<div class="graph-spacer ruled"> <div class="graph-spacer ruled">
<table id="graph-data" class="table graph-table" summary="Accessibility results from Pa11y for this page"> <table id="graph-data" class="table graph-table" summary="Accessibility results from Pa11y for this page">
<caption>Pa11y results for this URL</caption> <caption>Pa11y results for this URL</caption>
@@ -86,4 +85,5 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div> </div>

View File

@@ -32,15 +32,14 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
</div> </div>
</div> </div>
<div class="row date-selector-row"> <div class="row date-selector-row">
<div id="top" class="col-md-12 col-sm-12 clearfix"> <div class="col-md-12 col-sm-12 clearfix">
<div class="well dark-well"> <div class="well dark-well">
<div class="date-selector"> <div class="date-selector">
<div class="btn-group block-level clearfix"> <div class="btn-group block-level clearfix">
<h2 class="h4">
<span class="glyphicon glyphicon-calendar" aria-hidden="true"></span>&nbsp;&nbsp;{{date-format task.lastResult.date format="DD MMM YYYY"}} <h2 class="h3" id="dates-navigation">Select a date to show stats for: <span class="glyphicon glyphicon-calendar"></span></h2>
</h2>
<h3 class="h5 show-stats" id="dates-navigation">Select a date to show stats for:</h3>
<nav aria-labelledby="dates-navigation"> <nav aria-labelledby="dates-navigation">
<ul class="dates-list"> <ul class="dates-list">
{{#results}} {{#results}}
@@ -56,31 +55,32 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<div class="row"> <div class="row">
<div class="col-md-12 col-sm-12 clearfix"> <div class="col-md-12 col-sm-12 clearfix">
<div class="well"> <div class="well">
<h4 class="crunch-top">View results in browser</h4> <h2 class="crunch-top h3">View results in browser</h2>
<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> <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>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-9"> <section class="col-md-9" id="top">
<ul class="nav nav-tabs category-list" role="tablist"> <h2 id="tabSectionHeading" class="crunch-top">Results</h2>
<li class="category-list__item category-list__item_type_error active" role="presentation"> <ul class="nav nav-tabs category-list" aria-labelledby="tabSectionHeading" role="tablist">
<li class="category-list__item category-list__item_type_error active" aria-selected="true" role="presentation">
<a class="category-list__link" id="errors" href="#errors-list" aria-controls="errors-list" role="tab" data-toggle="tab" data-test="task-errors"> <a class="category-list__link" id="errors" href="#errors-list" aria-controls="errors-list" role="tab" data-toggle="tab" data-test="task-errors">
Errors ( {{mainResult.count.error}} ) Errors ( {{mainResult.count.error}} )
</a> </a>
</li> </li>
<li class="category-list__item category-list__item_type_warning" role="presentation"> <li class="category-list__item category-list__item_type_warning" aria-selected="false" role="presentation">
<a class="category-list__link" id="warnings" href="#warnings-list" aria-controls="warnings-list" role="tab" data-toggle="tab" data-test="task-warnings"> <a class="category-list__link" id="warnings" href="#warnings-list" aria-controls="warnings-list" role="tab" data-toggle="tab" data-test="task-warnings">
Warnings ( {{mainResult.count.warning}} ) Warnings ( {{mainResult.count.warning}} )
</a> </a>
</li> </li>
<li class="category-list__item category-list__item_type_notice" role="presentation"> <li class="category-list__item category-list__item_type_notice" aria-selected="false" role="presentation">
<a class="category-list__link" id="notices" href="#notices-list" aria-controls="notices-list" role="tab" data-toggle="tab" data-test="task-notices"> <a class="category-list__link" id="notices" href="#notices-list" aria-controls="notices-list" role="tab" data-toggle="tab" data-test="task-notices">
Notices ( {{mainResult.count.notice}} ) Notices ( {{mainResult.count.notice}} )
</a> </a>
</li> </li>
<li class="category-list__item category-list__item_type_ignore" role="presentation"> <li class="category-list__item category-list__item_type_ignore" aria-selected="false" role="presentation">
<a class="category-list__link" id="ignore" href="#ignore-list" aria-controls="ignore-list" role="tab" data-toggle="tab"> <a class="category-list__link" id="ignore" href="#ignore-list" aria-controls="ignore-list" role="tab" data-toggle="tab">
Ignored rules ( {{mainResult.ignore.length}} ) Ignored rules ( {{mainResult.ignore.length}} )
</a> </a>
@@ -88,7 +88,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div id="errors-list" role="tabpanel" class="tab-pane tasks-list fade in active"> <div id="errors-list" role="tabpanel" class="tab-pane tasks-list fade in active" aria-labelledby="errors">
{{#if mainResult.count.error}} {{#if mainResult.count.error}}
{{#mainResult.errors}} {{#mainResult.errors}}
<div class="panel panel-default task task_type_error"> <div class="panel panel-default task task_type_error">
@@ -147,14 +147,14 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
{{/mainResult.errors}} {{/mainResult.errors}}
<div class="to-top"> <div class="to-top">
<a class="link" href="#top" data-role="top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a> <a class="link" href="#top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a>
</div> </div>
{{else}} {{else}}
<div class="text">Well done! You have 0 errors. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div> <div class="text">Well done! You have 0 errors. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div>
{{/if}} {{/if}}
</div> </div>
<div id="warnings-list" role="tabpanel" class="tab-pane tasks-list fade"> <div id="warnings-list" role="tabpanel" class="tab-pane tasks-list fade" aria-labelledby="warning">
{{#if mainResult.count.warning}} {{#if mainResult.count.warning}}
{{#mainResult.warnings}} {{#mainResult.warnings}}
<div class="panel panel-default task task_type_warning"> <div class="panel panel-default task task_type_warning">
@@ -213,14 +213,14 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
{{/mainResult.warnings}} {{/mainResult.warnings}}
<div class="to-top"> <div class="to-top">
<a class="link" href="#top" data-role="top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a> <a class="link" href="#top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a>
</div> </div>
{{else}} {{else}}
<div class="text">Well done! You have 0 warnings. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div> <div class="text">Well done! You have 0 warnings. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div>
{{/if}} {{/if}}
</div> </div>
<div id="notices-list" role="tabpanel" class="tab-pane tasks-list fade"> <div id="notices-list" role="tabpanel" class="tab-pane tasks-list fade" aria-labelledby="notices">
{{#if mainResult.count.notice}} {{#if mainResult.count.notice}}
{{#mainResult.notices}} {{#mainResult.notices}}
<div class="panel panel-default task task_type_notice"> <div class="panel panel-default task task_type_notice">
@@ -279,14 +279,14 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
{{/mainResult.notices}} {{/mainResult.notices}}
<div class="to-top"> <div class="to-top">
<a class="link" href="#top" data-role="top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a> <a class="link" href="#top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a>
</div> </div>
{{else}} {{else}}
<div class="text">Well done! You have 0 notices. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div> <div class="text">Well done! You have 0 notices. <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span></div>
{{/if}} {{/if}}
</div> </div>
<div id="ignore-list" role="tabpanel" class="tab-pane tasks-list fade"> <div id="ignore-list" role="tabpanel" class="tab-pane tasks-list fade" aria-labelledby="ignore">
{{#if mainResult.ignore.length}} {{#if mainResult.ignore.length}}
{{#mainResult.ignore}} {{#mainResult.ignore}}
<div class="panel panel-default task task_type_ignore"> <div class="panel panel-default task task_type_ignore">
@@ -316,11 +316,11 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
{{/mainResult.ignore}} {{/mainResult.ignore}}
<div class="to-top"> <div class="to-top">
<a class="link" href="#top" data-role="top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a> <a class="link" href="#top"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>Back to top</a>
</div> </div>
{{else}} {{else}}
<div class="text">You have no ignored rules.</div> <div class="text">You have no ignored rules.</div>
{{/if}} {{/if}}
</div> </div>
</div> </div>
</div> </section>

View File

@@ -14,7 +14,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>. along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
}} }}
<div class="col-md-12 zfix"> <section 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-12"> <div class="col-md-12">
@@ -41,4 +41,4 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
</div> </div>
</div> </div>
</div> </section>

View File

@@ -25,7 +25,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
<li class="col-md-4 col-sm-6 task-card add-task"> <li class="col-md-4 col-sm-6 task-card add-task">
<a class="well task-card-link crunch-bottom" data-role="add-task" href="/new" data-test="add-task"> <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" aria-hidden="true">+</p>
</a> </a>
</li> </li>
{{/unless}} {{/unless}}
@@ -56,8 +56,8 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{#unless ../readonly}} {{#unless ../readonly}}
<div class="btn-group options-button text-right"> <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> <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>
<nav aria-label="task tools"> <nav class="dropdown-menu pull-right" aria-label="task tools">
<ul class="dropdown-menu pull-right"> <ul class="options-menu">
<li><a href="{{href}}/edit">Edit this task</a></li> <li><a href="{{href}}/edit">Edit this task</a></li>
<li><a href="{{href}}/delete">Delete this task</a></li> <li><a href="{{href}}/delete">Delete this task</a></li>
<li class="divider"></li> <li class="divider"></li>

View File

@@ -22,7 +22,7 @@ module.exports = presentIgnoreRules;
function presentIgnoreRules(ignore) { function presentIgnoreRules(ignore) {
return ignore.map(name => { return ignore.map(name => {
return { return {
name: name, name,
description: rules[name] description: rules[name]
}; };
}); });

View File

@@ -16,7 +16,7 @@ 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"}} Pa11y Dashboard Results - {{task.name}} - {{date-format mainResult.date format="DD MMM YYYY"}}
{{/content}} {{/content}}
{{> result-header}} {{> result-header}}

View File

@@ -22,7 +22,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{#edited}} {{#edited}}
<div class="col-md-12 clearfix" data-test="alert"> <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" aria-label="Close">×</button>
<strong>Success!</strong> <strong>Success!</strong>
<p>Your changes have been saved.</p> <p>Your changes have been saved.</p>
</div> </div>
@@ -146,7 +146,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
</div> </div>
</div> </div>
<p class="control-label"><b>Ignore these rules</b> <a target="_blank" href="https://github.com/pa11y/pa11y/wiki/HTML-CodeSniffer-Rules">(full list of rules here)</a></p> <p class="control-label"><b>Ignore these rules</b> (<a target="_blank" href="https://github.com/pa11y/pa11y/wiki/HTML-CodeSniffer-Rules">full list of rules here</a>) <a href="#submitEditBtn" id="skipRules">Skip list of rules</a></p>
<div class="standards-lists"> <div class="standards-lists">
{{#standards}} {{#standards}}
@@ -166,7 +166,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{/standards}} {{/standards}}
</div> </div>
<button type="submit" class="btn btn-success">Save changes <span class="glyphicon glyphicon-save"></span></button> <button type="submit" id="submitEditBtn" 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> <a href="/{{task.id}}/edit" class="btn btn-primary">Undo <span class="glyphicon glyphicon-refresh"></span></a>
</form> </form>

View File

@@ -16,13 +16,13 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
}} }}
{{#content "title"}} {{#content "title"}}
{{task.name}} - {{simplify-url task.url}} ({{task.standard}}) Pa11y Dashboard Results for {{task.name}} - ({{task.standard}})
{{/content}} {{/content}}
{{#added}} {{#added}}
<div class="col-md-12 clearfix" data-test="alert"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button data-dismiss="alert" class="close" type="button">×</button> <button data-dismiss="alert" class="close" type="button" aria-label="Close">×</button>
<strong>Whoop whoop!</strong> <strong>Whoop whoop!</strong>
<p>Your new URL has been added.</p> <p>Your new URL has been added.</p>
</div> </div>
@@ -32,7 +32,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{#running}} {{#running}}
<div class="col-md-12 clearfix" data-test="alert"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button data-dismiss="alert" class="close" type="button">×</button> <button data-dismiss="alert" class="close" type="button" aria-label="Close">×</button>
<strong>New results incoming!</strong> <strong>New results incoming!</strong>
<p> <p>
New results are being generated for this URL in the background. New results are being generated for this URL in the background.
@@ -45,7 +45,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{#ruleIgnored}} {{#ruleIgnored}}
<div class="col-md-12 clearfix" data-test="alert"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button data-dismiss="alert" class="close" type="button">×</button> <button data-dismiss="alert" class="close" type="button" aria-label="Close">×</button>
<strong>Rule ignored!</strong> <strong>Rule ignored!</strong>
<p> <p>
You've ignored an accessibility rule for this URL. You've ignored an accessibility rule for this URL.
@@ -58,7 +58,7 @@ along with Pa11y Dashboard. If not, see <http://www.gnu.org/licenses/>.
{{#ruleUnignored}} {{#ruleUnignored}}
<div class="col-md-12 clearfix" data-test="alert"> <div class="col-md-12 clearfix" data-test="alert">
<div class="alert alert-success"> <div class="alert alert-success">
<button data-dismiss="alert" class="close" type="button">×</button> <button data-dismiss="alert" class="close" type="button" aria-label="Close">×</button>
<strong>Rule unignored!</strong> <strong>Rule unignored!</strong>
<p> <p>
You've removed an ignored accessibility rule for this URL. You've removed an ignored accessibility rule for this URL.