Browse Source

Add Per Soderlind's WCAG validator.

pull/27/head
Ned Zimmerman 7 years ago
parent
commit
bff87e3e08
No known key found for this signature in database
GPG Key ID: FF56334A013120CA
  1. 15
      app/admin.php
  2. 59
      lib/customizer-validate-wcag-color-contrast/README.md
  3. 210
      lib/customizer-validate-wcag-color-contrast/customizer-validate-wcag-color-contrast.js

15
app/admin.php

@ -136,3 +136,18 @@ add_action('customize_preview_init', function () {
wp_enqueue_script('aldine/customizer.js', asset_path('scripts/customizer.js'), ['customize-preview'], null, true);
wp_localize_script('aldine/customizer.js', 'SAGE_DIST_PATH', get_theme_file_uri() . '/dist/');
});
add_action('customize_controls_enqueue_scripts', function () {
$handle = 'wcag-validate-customizer-color-contrast';
$src = get_theme_file_uri() . '/lib/customizer-validate-wcag-color-contrast/customizer-validate-wcag-color-contrast.js';
$deps = [ 'customize-controls' ];
wp_enqueue_script($handle, $src, $deps);
$exports = [
'validate_color_contrast' => [
'pb_network_color_primary_fg' => [ 'pb_network_color_primary' ],
'pb_network_color_accent_fg' => [ 'pb_network_color_accent' ],
],
];
wp_scripts()->add_data($handle, 'data', sprintf('var _validateWCAGColorContrastExports = %s;', wp_json_encode($exports)));
});

59
lib/customizer-validate-wcag-color-contrast/README.md

@ -0,0 +1,59 @@
# Validate WCAG Color Contrast for Customizer Color Control
The validator measures the color contrast between 2 or more color controls. It will post a warning if the contrast is less than 4.5
BTW, if the contrast >= 7, the score is a WCAG AAA. If the contrast is between 7 and 4.5 the score is a WCAG AA.
<img src="assets/wcag-color-contrast.gif" width="650" />
## Demo
I've added this validator to my [customizer demo theme](https://github.com/soderlind/2016-customizer-demo).
## Installing the validator
Clone this repository and include the [javascript code](customizer-validate-wcag-color-contrast.js):
```php
/**
* Enqueue customizer control scripts.
*/
add_action( 'customize_controls_enqueue_scripts', 'on_customize_controls_enqueue_scripts' );
function on_customize_controls_enqueue_scripts() {
$handle = 'wcag-validate-customizer-color-contrast';
$src = get_stylesheet_directory_uri() . '/js/customizer-validate-wcag-color-contrast.js';
$deps = [ 'customize-controls' ];
wp_enqueue_script( $handle, $src, $deps );
$exports = [
'validate_color_contrast' => [
// key = current color control , values = array with color controls to check color contrast against
'page_background_color' => [ 'main_text_color', 'secondary_text_color' ],
'main_text_color' => [ 'page_background_color' ],
'secondary_text_color' => [ 'page_background_color' ],
],
];
wp_scripts()->add_data( $handle, 'data', sprintf( 'var _validateWCAGColorContrastExports = %s;', wp_json_encode( $exports ) ) );
}
```
**Note:** You have to add color control setting ids to the `validate_color_contrast` above. See inline comment.
## Credits ##
- [WCAG contrast ratio measurement and scoring](https://github.com/tmcw/wcag-contrast) - Copyright (c) 2017, Tom MacWright. All rights reserved.
- [hex-rgb](https://github.com/sindresorhus/hex-rgb) - Copyright (c) Sindre Sorhus
- [relative-luminance](https://github.com/tmcw/relative-luminance)
## Copyright and License
The Validate WCAG Color Contrast for Customizer Color Control is copyright 2017 Per Soderlind
The Validate WCAG Color Contrast for Customizer Color Control 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 2 of the License, or (at your option) any later version.
The Validate WCAG Color Contrast for Customizer Color Control 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 Lesser General Public License along with the Extension. If not, see http://www.gnu.org/licenses/.

210
lib/customizer-validate-wcag-color-contrast/customizer-validate-wcag-color-contrast.js

@ -0,0 +1,210 @@
/* global wp, _validateWCAGColorContrastExports */
/* exported validateWCAGColorContrast */
var validateWCAGColorContrast = ( function( $, api, exports ) {
var self = {
validate_color_contrast: []
};
if ( exports ) {
$.extend( self, exports );
}
/**
* Add contrast validation to a control if it is entitled (is a valid color control).
*
* @param {wp.customize.Control} setting - Control.
* @param {wp.customize.Value} setting.validationMessage - Validation message.
* @return {boolean} Whether validation was added.
*/
self.addWCAGColorContrastValidation = function( setting ) {
var initialValidate;
if ( ! self.isColorControl( setting ) ) {
return false;
}
initialValidate = setting.validate;
/**
* Wrap the setting's validate() method to do validation on the value to be sent to the server.
*
* @param {mixed} value - New value being assigned to the setting.
* @returns {*}
*/
setting.validate = function( value ) {
var setting = this, title, validationError;
var current_color = value;
var current_id = this.id;
var all_color_controls = _.union( _.flatten( _.values( self.validate_color_contrast ) ) );
// remove other (old) notifications
_.each ( _.without ( all_color_controls , current_id ), function( other_color_control_id ) {
var other_control = api.control.instance( other_color_control_id );
notice = other_control.container.find('.notice');
notice.hide();
} );
// find other color controls and check contrast with current color control
var other_color_controls = self.validate_color_contrast[ current_id ];
_.each ( other_color_controls, function( other_color_control_id ) {
var other_control = api.control.instance( other_color_control_id);
var other_color = other_control.container.find('.color-picker-hex').val();
var name = $( '#customize-control-' + other_color_control_id + ' .customize-control-title').text();
var contrast = self.hex( current_color, other_color );
var score = self.score( contrast );
// contrast >= 7 ? "AAA" : contrast >= 4.5 ? "AA" : ""
if ( contrast < 4.5 ) {
setting.notifications.remove( other_color_control_id );
validationWarning = new api.Notification( other_color_control_id, { message: self.sprintf( 'WCAG conflict with "%s"<br/>contrast: %s' ,name, contrast), type: 'warning' } );
setting.notifications.add( validationWarning.code, validationWarning );
// console.log( color_control_id + ' ' + color + ' ' + contrast + ' ' + score );
} else {
setting.notifications.remove( other_color_control_id );
}
} );
return value;
};
return true;
};
/**
* Return whether the setting is entitled (i.e. if it is a title or has a title).
*
* @param {wp.customize.Setting} setting - Setting.
* @returns {boolean}
*/
self.isColorControl = function( setting ) {
return _.findKey( self.validate_color_contrast, function( key, value ) {
return value == setting.id;
} );
};
api.bind( 'add', function( setting ) {
self.addWCAGColorContrastValidation( setting );
} );
self.sprintf = function( format ) {
for( var i=1; i < arguments.length; i++ ) {
format = format.replace( /%s/, arguments[i] );
}
return format;
};
/**
* Methods used to calculate WCAG Color Contrast
*/
// from https://github.com/sindresorhus/hex-rgb
self.hexRgb = function (hex) {
if (typeof hex !== 'string') {
throw new TypeError('Expected a string');
}
hex = hex.replace(/^#/, '');
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
var num = parseInt(hex, 16);
return [num >> 16, num >> 8 & 255, num & 255];
};
// from https://github.com/tmcw/relative-luminance
// # Relative luminance
//
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
// https://en.wikipedia.org/wiki/Luminance_(relative)
// https://en.wikipedia.org/wiki/Luminosity_function
// https://en.wikipedia.org/wiki/Rec._709#Luma_coefficients
// red, green, and blue coefficients
var rc = 0.2126,
gc = 0.7152,
bc = 0.0722,
// low-gamma adjust coefficient
lowc = 1 / 12.92;
self.adjustGamma = function( g ) {
return Math.pow((g + 0.055) / 1.055, 2.4);
};
/**
* Given a 3-element array of R, G, B varying from 0 to 255, return the luminance
* as a number from 0 to 1.
* @param {Array<number>} rgb 3-element array of a color
* @returns {number} luminance, between 0 and 1
* @example
* var luminance = require('relative-luminance');
* var black_lum = luminance([0, 0, 0]); // 0
*/
self.relativeLuminance = function (rgb) {
var rsrgb = rgb[0] / 255;
var gsrgb = rgb[1] / 255;
var bsrgb = rgb[2] / 255;
var r = rsrgb <= 0.03928 ? rsrgb * lowc : self.adjustGamma(rsrgb),
g = gsrgb <= 0.03928 ? gsrgb * lowc : self.adjustGamma(gsrgb),
b = bsrgb <= 0.03928 ? bsrgb * lowc : self.adjustGamma(bsrgb);
return r * rc + g * gc + b * bc;
};
// from https://github.com/tmcw/wcag-contrast
/**
* Get the contrast ratio between two relative luminance values
* @param {number} a luminance value
* @param {number} b luminance value
* @returns {number} contrast ratio
* @example
* luminance(1, 1); // = 1
*/
self.luminance = function(a, b) {
var l1 = Math.max(a, b);
var l2 = Math.min(a, b);
return (l1 + 0.05) / (l2 + 0.05);
};
/**
* Get a score for the contrast between two colors as rgb triplets
* @param {array} a
* @param {array} b
* @returns {number} contrast ratio
* @example
* rgb([0, 0, 0], [255, 255, 255]); // = 21
*/
self.rgb = function(a, b) {
return self.luminance(self.relativeLuminance(a), self.relativeLuminance(b));
};
/**
* Get a score for the contrast between two colors as hex strings
* @param {string} a hex value
* @param {string} b hex value
* @returns {number} contrast ratio
* @example
* hex('#000', '#fff'); // = 21
*/
self.hex = function(a, b) {
return self.rgb(self.hexRgb(a), self.hexRgb(b));
};
/**
* Get a textual score from a numeric contrast value
* @param {number} contrast
* @returns {string} score
* @example
* score(10); // = 'AAA'
*/
self.score = function(contrast) {
return contrast >= 7 ? "AAA" : contrast >= 4.5 ? "AA" : "";
};
return self;
}( jQuery, wp.customize, _validateWCAGColorContrastExports ) );
Loading…
Cancel
Save