$formError.addClass(this.options.formErrorClass);
}
- $el.addClass(this.options.inputErrorClass).attr('data-invalid', '');
+ $el.addClass(this.options.inputErrorClass).attr({
+ 'data-invalid': '',
+ 'aria-invalid': true
+ });
+ }
+
+ /**
+ * Adds [for] and [role=alert] attributes to all form error targetting $el,
+ * and [aria-describedby] attribute to $el toward the first form error.
+ * @param {Object} $el - jQuery object
+ */
+ addA11yAttributes($el) {
+ let $errors = this.findFormError($el);
+ let $labels = $errors.filter('label').end();
+ let $error = $errors.first().end();
+ if (!$errors.length) return;
+
+ // Set [aria-describedby] on the input toward the first form error if it is not set
+ if (typeof $el.attr('aria-describedby') === 'undefined') {
+ // Get the first error ID or create one
+ let errorId = $error.attr('id');
+ if (typeof errorId === 'undefined') {
+ errorId = GetYoDigits(6, 'abide-error');
+ $error.attr('id', errorId);
+ };
+
+ $el.attr('aria-describedby', errorId);
+ }
+
+ if ($labels.filter('[for]').length < $labels.length) {
+ // Get the input ID or create one
+ let elemId = $el.attr('id');
+ if (typeof elemId === 'undefined') {
+ elemId = GetYoDigits(6, 'abide-input');
+ $el.attr('id', elemId);
+ };
+
+ // For each label targeting $el, set [for] if it is not set.
+ $labels.each((i, label) => {
+ const $label = $(label);
+ if (typeof $label.attr('for') === 'undefined')
+ $label.attr('for', elemId);
+ }).end();
+ }
+
+ // For each error targeting $el, set [role=alert] if it is not set.
+ $errors.each((i, label) => {
+ const $label = $(label);
+ if (typeof $label.attr('role') === 'undefined')
+ $label.attr('role', 'alert');
+ }).end();
+ }
+
+ /**
+ * Adds [aria-live] attribute to the given global form error $el.
+ * @param {Object} $el - jQuery object to add the attribute to
+ */
+ addGlobalErrorA11yAttributes($el) {
+ if (typeof $el.attr('aria-live') === 'undefined')
+ $el.attr('aria-live', this.options.a11yErrorLevel);
}
/**
"homepage": "http://foundation.zurb.com/sites",
"scripts": {
"start": "gulp",
- "test": "npm run test:sass && npm run test:javascript:phantomjs",
+ "test": "npm run test:sass && npm run test:javascript:units",
"test:ci": "npm run test:sass && npm run test:javascript:ci",
"test:sass": "mocha test/sass/test_sass.js",
"test:javascript:transpile": "gulp sass:foundation && gulp test:transpile-js",
- "test:javascript:phantomjs": "npm run test:javascript:transpile && mocha-phantomjs --ignore-resource-errors test/javascript/index.html",
+ "test:javascript:units": "npm run test:javascript:transpile && mocha-headless-chrome -a ignore-resource-errors -f test/javascript/index.html",
"test:javascript:browserstack": "npm run test:javascript:transpile && browserstack-runner",
- "test:javascript:ci": "npm run test:javascript:transpile && mocha-phantomjs --ignore-resource-errors test/javascript/index.html && browserstack-runner",
+ "test:javascript:ci": "npm run test:javascript:transpile && mocha-headless-chrome -a ignore-resource-errors -f test/javascript/index.html && browserstack-runner",
"test:visual": "gulp test",
"deploy": "gulp deploy",
"deploy:prep": "gulp deploy:prep",
"is-empty-object": "^1.1.1",
"js-yaml": "^3.8.4",
"mocha": "^3.4.2",
- "mocha-phantomjs": "^4.0.2",
+ "mocha-headless-chrome": "^1.8.2",
"motion-ui": "^1.1.0",
"multiline": "^1.0.2",
"normalize-scss": "6.0.0",