angular-material-npfixed
Version:
The Angular Material project is an implementation of Material Design in Angular.js. This project provides a set of reusable, well-tested, and accessible Material Design UI components. Angular Material is supported internally at Google by the Angular.js, M
176 lines (150 loc) • 4.76 kB
JavaScript
/**
* @ngdoc module
* @name material.core.aria
* @description
* Aria Expectations for ngMaterial components.
*/
angular
.module('material.core')
.provider('$mdAria', MdAriaProvider);
/**
* @ngdoc service
* @name $mdAriaProvider
* @module material.core.aria
*
* @description
*
* Modify options of the `$mdAria` service, which will be used by most of the Angular Material
* components.
*
* You are able to disable `$mdAria` warnings, by using the following markup.
*
* <hljs lang="js">
* app.config(function($mdAriaProvider) {
* // Globally disables all ARIA warnings.
* $mdAriaProvider.disableWarnings();
* });
* </hljs>
*
*/
function MdAriaProvider() {
var config = {
/** Whether we should show ARIA warnings in the console if labels are missing on the element */
showWarnings: true
};
return {
disableWarnings: disableWarnings,
$get: function($$rAF, $log, $window, $interpolate) {
return MdAriaService.apply(config, arguments);
}
};
/**
* @ngdoc method
* @name $mdAriaProvider#disableWarnings
* @description Disables all ARIA warnings generated by Angular Material.
*/
function disableWarnings() {
config.showWarnings = false;
}
}
/*
* @ngInject
*/
function MdAriaService($$rAF, $log, $window, $interpolate) {
// Load the showWarnings option from the current context and store it inside of a scope variable,
// because the context will be probably lost in some function calls.
var showWarnings = this.showWarnings;
return {
expect: expect,
expectAsync: expectAsync,
expectWithText: expectWithText,
expectWithoutText: expectWithoutText,
getText: getText
};
/**
* Check if expected attribute has been specified on the target element or child
* @param element
* @param attrName
* @param {optional} defaultValue What to set the attr to if no value is found
*/
function expect(element, attrName, defaultValue) {
var node = angular.element(element)[0] || element;
// if node exists and neither it nor its children have the attribute
if (node &&
((!node.hasAttribute(attrName) ||
node.getAttribute(attrName).length === 0) &&
!childHasAttribute(node, attrName))) {
defaultValue = angular.isString(defaultValue) ? defaultValue.trim() : '';
if (defaultValue.length) {
element.attr(attrName, defaultValue);
} else if (showWarnings) {
$log.warn('ARIA: Attribute "', attrName, '", required for accessibility, is missing on node:', node);
}
}
}
function expectAsync(element, attrName, defaultValueGetter) {
// Problem: when retrieving the element's contents synchronously to find the label,
// the text may not be defined yet in the case of a binding.
// There is a higher chance that a binding will be defined if we wait one frame.
$$rAF(function() {
expect(element, attrName, defaultValueGetter());
});
}
function expectWithText(element, attrName) {
var content = getText(element) || "";
var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;
if (hasBinding) {
expectAsync(element, attrName, function() {
return getText(element);
});
} else {
expect(element, attrName, content);
}
}
function expectWithoutText(element, attrName) {
var content = getText(element);
var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;
if ( !hasBinding && !content) {
expect(element, attrName, content);
}
}
function getText(element) {
element = element[0] || element;
var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
var text = '';
var node;
while (node = walker.nextNode()) {
if (!isAriaHiddenNode(node)) {
text += node.textContent;
}
}
return text.trim() || '';
function isAriaHiddenNode(node) {
while (node.parentNode && (node = node.parentNode) !== element) {
if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {
return true;
}
}
}
}
function childHasAttribute(node, attrName) {
var hasChildren = node.hasChildNodes(),
hasAttr = false;
function isHidden(el) {
var style = el.currentStyle ? el.currentStyle : $window.getComputedStyle(el);
return (style.display === 'none');
}
if (hasChildren) {
var children = node.childNodes;
for (var i=0; i < children.length; i++) {
var child = children[i];
if (child.nodeType === 1 && child.hasAttribute(attrName)) {
if (!isHidden(child)) {
hasAttr = true;
}
}
}
}
return hasAttr;
}
}