diff options
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/angular-material/modules/js/core/core.js')
-rw-r--r-- | ecomp-portal-FE/client/bower_components/angular-material/modules/js/core/core.js | 3779 |
1 files changed, 0 insertions, 3779 deletions
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/core/core.js b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/core/core.js deleted file mode 100644 index 66c2fc46..00000000 --- a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/core/core.js +++ /dev/null @@ -1,3779 +0,0 @@ -/*! - * Angular Material Design - * https://github.com/angular/material - * @license MIT - * v0.9.8 - */ -(function( window, angular, undefined ){ -"use strict"; - - -/** - * Initialization function that validates environment - * requirements. - */ -angular - .module('material.core', [ 'material.core.gestures', 'material.core.theming' ]) - .config( MdCoreConfigure ); - - -function MdCoreConfigure($provide, $mdThemingProvider) { - - $provide.decorator('$$rAF', ["$delegate", rAFDecorator]); - - $mdThemingProvider.theme('default') - .primaryPalette('indigo') - .accentPalette('pink') - .warnPalette('red') - .backgroundPalette('grey'); -} -MdCoreConfigure.$inject = ["$provide", "$mdThemingProvider"]; - -function rAFDecorator( $delegate ) { - /** - * Use this to throttle events that come in often. - * The throttled function will always use the *last* invocation before the - * coming frame. - * - * For example, window resize events that fire many times a second: - * If we set to use an raf-throttled callback on window resize, then - * our callback will only be fired once per frame, with the last resize - * event that happened before that frame. - * - * @param {function} callback function to debounce - */ - $delegate.throttle = function(cb) { - var queueArgs, alreadyQueued, queueCb, context; - return function debounced() { - queueArgs = arguments; - context = this; - queueCb = cb; - if (!alreadyQueued) { - alreadyQueued = true; - $delegate(function() { - queueCb.apply(context, queueArgs); - alreadyQueued = false; - }); - } - }; - }; - return $delegate; -} - -angular.module('material.core') -.factory('$mdConstant', MdConstantFactory); - -function MdConstantFactory($$rAF, $sniffer) { - - var webkit = /webkit/i.test($sniffer.vendorPrefix); - function vendorProperty(name) { - return webkit ? ('webkit' + name.charAt(0).toUpperCase() + name.substring(1)) : name; - } - - return { - KEY_CODE: { - ENTER: 13, - ESCAPE: 27, - SPACE: 32, - LEFT_ARROW : 37, - UP_ARROW : 38, - RIGHT_ARROW : 39, - DOWN_ARROW : 40, - TAB : 9, - BACKSPACE: 8, - DELETE: 46 - }, - CSS: { - /* Constants */ - TRANSITIONEND: 'transitionend' + (webkit ? ' webkitTransitionEnd' : ''), - ANIMATIONEND: 'animationend' + (webkit ? ' webkitAnimationEnd' : ''), - - TRANSFORM: vendorProperty('transform'), - TRANSFORM_ORIGIN: vendorProperty('transformOrigin'), - TRANSITION: vendorProperty('transition'), - TRANSITION_DURATION: vendorProperty('transitionDuration'), - ANIMATION_PLAY_STATE: vendorProperty('animationPlayState'), - ANIMATION_DURATION: vendorProperty('animationDuration'), - ANIMATION_NAME: vendorProperty('animationName'), - ANIMATION_TIMING: vendorProperty('animationTimingFunction'), - ANIMATION_DIRECTION: vendorProperty('animationDirection') - }, - MEDIA: { - 'sm': '(max-width: 600px)', - 'gt-sm': '(min-width: 600px)', - 'md': '(min-width: 600px) and (max-width: 960px)', - 'gt-md': '(min-width: 960px)', - 'lg': '(min-width: 960px) and (max-width: 1200px)', - 'gt-lg': '(min-width: 1200px)' - }, - MEDIA_PRIORITY: [ - 'gt-lg', - 'lg', - 'gt-md', - 'md', - 'gt-sm', - 'sm' - ] - }; -} -MdConstantFactory.$inject = ["$$rAF", "$sniffer"]; - - angular - .module('material.core') - .config( ["$provide", function($provide){ - $provide.decorator('$mdUtil', ['$delegate', function ($delegate){ - /** - * Inject the iterator facade to easily support iteration and accessors - * @see iterator below - */ - $delegate.iterator = MdIterator; - - return $delegate; - } - ]); - }]); - - /** - * iterator is a list facade to easily support iteration and accessors - * - * @param items Array list which this iterator will enumerate - * @param reloop Boolean enables iterator to consider the list as an endless reloop - */ - function MdIterator(items, reloop) { - var trueFn = function() { return true; }; - - if (items && !angular.isArray(items)) { - items = Array.prototype.slice.call(items); - } - - reloop = !!reloop; - var _items = items || [ ]; - - // Published API - return { - items: getItems, - count: count, - - inRange: inRange, - contains: contains, - indexOf: indexOf, - itemAt: itemAt, - - findBy: findBy, - - add: add, - remove: remove, - - first: first, - last: last, - next: angular.bind(null, findSubsequentItem, false), - previous: angular.bind(null, findSubsequentItem, true), - - hasPrevious: hasPrevious, - hasNext: hasNext - - }; - - /** - * Publish copy of the enumerable set - * @returns {Array|*} - */ - function getItems() { - return [].concat(_items); - } - - /** - * Determine length of the list - * @returns {Array.length|*|number} - */ - function count() { - return _items.length; - } - - /** - * Is the index specified valid - * @param index - * @returns {Array.length|*|number|boolean} - */ - function inRange(index) { - return _items.length && ( index > -1 ) && (index < _items.length ); - } - - /** - * Can the iterator proceed to the next item in the list; relative to - * the specified item. - * - * @param item - * @returns {Array.length|*|number|boolean} - */ - function hasNext(item) { - return item ? inRange(indexOf(item) + 1) : false; - } - - /** - * Can the iterator proceed to the previous item in the list; relative to - * the specified item. - * - * @param item - * @returns {Array.length|*|number|boolean} - */ - function hasPrevious(item) { - return item ? inRange(indexOf(item) - 1) : false; - } - - /** - * Get item at specified index/position - * @param index - * @returns {*} - */ - function itemAt(index) { - return inRange(index) ? _items[index] : null; - } - - /** - * Find all elements matching the key/value pair - * otherwise return null - * - * @param val - * @param key - * - * @return array - */ - function findBy(key, val) { - return _items.filter(function(item) { - return item[key] === val; - }); - } - - /** - * Add item to list - * @param item - * @param index - * @returns {*} - */ - function add(item, index) { - if ( !item ) return -1; - - if (!angular.isNumber(index)) { - index = _items.length; - } - - _items.splice(index, 0, item); - - return indexOf(item); - } - - /** - * Remove item from list... - * @param item - */ - function remove(item) { - if ( contains(item) ){ - _items.splice(indexOf(item), 1); - } - } - - /** - * Get the zero-based index of the target item - * @param item - * @returns {*} - */ - function indexOf(item) { - return _items.indexOf(item); - } - - /** - * Boolean existence check - * @param item - * @returns {boolean} - */ - function contains(item) { - return item && (indexOf(item) > -1); - } - - /** - * Return first item in the list - * @returns {*} - */ - function first() { - return _items.length ? _items[0] : null; - } - - /** - * Return last item in the list... - * @returns {*} - */ - function last() { - return _items.length ? _items[_items.length - 1] : null; - } - - /** - * Find the next item. If reloop is true and at the end of the list, it will go back to the - * first item. If given, the `validate` callback will be used to determine whether the next item - * is valid. If not valid, it will try to find the next item again. - * - * @param {boolean} backwards Specifies the direction of searching (forwards/backwards) - * @param {*} item The item whose subsequent item we are looking for - * @param {Function=} validate The `validate` function - * @param {integer=} limit The recursion limit - * - * @returns {*} The subsequent item or null - */ - function findSubsequentItem(backwards, item, validate, limit) { - validate = validate || trueFn; - - var curIndex = indexOf(item); - while (true) { - if (!inRange(curIndex)) return null; - - var nextIndex = curIndex + (backwards ? -1 : 1); - var foundItem = null; - if (inRange(nextIndex)) { - foundItem = _items[nextIndex]; - } else if (reloop) { - foundItem = backwards ? last() : first(); - nextIndex = indexOf(foundItem); - } - - if ((foundItem === null) || (nextIndex === limit)) return null; - if (validate(foundItem)) return foundItem; - - if (angular.isUndefined(limit)) limit = nextIndex; - - curIndex = nextIndex; - } - } - } - - -angular.module('material.core') -.factory('$mdMedia', mdMediaFactory); - -/** - * @ngdoc service - * @name $mdMedia - * @module material.core - * - * @description - * `$mdMedia` is used to evaluate whether a given media query is true or false given the - * current device's screen / window size. The media query will be re-evaluated on resize, allowing - * you to register a watch. - * - * `$mdMedia` also has pre-programmed support for media queries that match the layout breakpoints. - * (`sm`, `gt-sm`, `md`, `gt-md`, `lg`, `gt-lg`). - * - * @returns {boolean} a boolean representing whether or not the given media query is true or false. - * - * @usage - * <hljs lang="js"> - * app.controller('MyController', function($mdMedia, $scope) { - * $scope.$watch(function() { return $mdMedia('lg'); }, function(big) { - * $scope.bigScreen = big; - * }); - * - * $scope.screenIsSmall = $mdMedia('sm'); - * $scope.customQuery = $mdMedia('(min-width: 1234px)'); - * $scope.anotherCustom = $mdMedia('max-width: 300px'); - * }); - * </hljs> - */ - -function mdMediaFactory($mdConstant, $rootScope, $window) { - var queries = {}; - var mqls = {}; - var results = {}; - var normalizeCache = {}; - - $mdMedia.getResponsiveAttribute = getResponsiveAttribute; - $mdMedia.getQuery = getQuery; - $mdMedia.watchResponsiveAttributes = watchResponsiveAttributes; - - return $mdMedia; - - function $mdMedia(query) { - var validated = queries[query]; - if (angular.isUndefined(validated)) { - validated = queries[query] = validate(query); - } - - var result = results[validated]; - if (angular.isUndefined(result)) { - result = add(validated); - } - - return result; - } - - function validate(query) { - return $mdConstant.MEDIA[query] || - ((query.charAt(0) !== '(') ? ('(' + query + ')') : query); - } - - function add(query) { - var result = mqls[query] = $window.matchMedia(query); - result.addListener(onQueryChange); - return (results[result.media] = !!result.matches); - } - - function onQueryChange(query) { - $rootScope.$evalAsync(function() { - results[query.media] = !!query.matches; - }); - } - - function getQuery(name) { - return mqls[name]; - } - - function getResponsiveAttribute(attrs, attrName) { - for (var i = 0; i < $mdConstant.MEDIA_PRIORITY.length; i++) { - var mediaName = $mdConstant.MEDIA_PRIORITY[i]; - if (!mqls[queries[mediaName]].matches) { - continue; - } - - var normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName); - if (attrs[normalizedName]) { - return attrs[normalizedName]; - } - } - - // fallback on unprefixed - return attrs[getNormalizedName(attrs, attrName)]; - } - - function watchResponsiveAttributes(attrNames, attrs, watchFn) { - var unwatchFns = []; - attrNames.forEach(function(attrName) { - var normalizedName = getNormalizedName(attrs, attrName); - if (attrs[normalizedName]) { - unwatchFns.push( - attrs.$observe(normalizedName, angular.bind(void 0, watchFn, null))); - } - - for (var mediaName in $mdConstant.MEDIA) { - normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName); - if (!attrs[normalizedName]) { - return; - } - - unwatchFns.push(attrs.$observe(normalizedName, angular.bind(void 0, watchFn, mediaName))); - } - }); - - return function unwatch() { - unwatchFns.forEach(function(fn) { fn(); }) - }; - } - - // Improves performance dramatically - function getNormalizedName(attrs, attrName) { - return normalizeCache[attrName] || - (normalizeCache[attrName] = attrs.$normalize(attrName)); - } -} -mdMediaFactory.$inject = ["$mdConstant", "$rootScope", "$window"]; - -/* - * This var has to be outside the angular factory, otherwise when - * there are multiple material apps on the same page, each app - * will create its own instance of this array and the app's IDs - * will not be unique. - */ -var nextUniqueId = 0; - -angular.module('material.core') -.factory('$mdUtil', ["$cacheFactory", "$document", "$timeout", "$q", "$window", "$mdConstant", function($cacheFactory, $document, $timeout, $q, $window, $mdConstant) { - var Util; - - function getNode(el) { - return el[0] || el; - } - - return Util = { - now: window.performance ? - angular.bind(window.performance, window.performance.now) : - Date.now, - - clientRect: function(element, offsetParent, isOffsetRect) { - var node = getNode(element); - offsetParent = getNode(offsetParent || node.offsetParent || document.body); - var nodeRect = node.getBoundingClientRect(); - - // The user can ask for an offsetRect: a rect relative to the offsetParent, - // or a clientRect: a rect relative to the page - var offsetRect = isOffsetRect ? - offsetParent.getBoundingClientRect() : - { left: 0, top: 0, width: 0, height: 0 }; - return { - left: nodeRect.left - offsetRect.left, - top: nodeRect.top - offsetRect.top, - width: nodeRect.width, - height: nodeRect.height - }; - }, - offsetRect: function(element, offsetParent) { - return Util.clientRect(element, offsetParent, true); - }, - // Disables scroll around the passed element. Goes up the DOM to find a - // disableTarget (a md-content that is scrolling, or the body as a fallback) - // and uses CSS/JS to prevent it from scrolling - disableScrollAround: function(element) { - element = element instanceof angular.element ? element[0] : element; - var parentEl = element; - var disableTarget; - - // Find the highest level scrolling md-content - while (parentEl = this.getClosest(parentEl, 'MD-CONTENT', true)) { - if (isScrolling(parentEl)) { - disableTarget = angular.element(parentEl)[0]; - } - } - - // Default to the body if no scrolling md-content - if (!disableTarget) { - disableTarget = $document[0].body; - if (!isScrolling(disableTarget)) return angular.noop; - } - - if (disableTarget.nodeName == 'BODY') { - return disableBodyScroll(); - } else { - return disableElementScroll(); - } - - // Creates a virtual scrolling mask to absorb touchmove, keyboard, scrollbar clicking, and wheel events - function disableElementScroll() { - var scrollMask = angular.element('<div class="md-scroll-mask"><div class="md-scroll-mask-bar"></div></div>'); - var computedStyle = $window.getComputedStyle(disableTarget); - var disableRect = disableTarget.getBoundingClientRect(); - var scrollWidth = disableRect.width - disableTarget.clientWidth; - applyStyles(scrollMask[0], { - zIndex: computedStyle.zIndex == 'auto' ? 2 : computedStyle.zIndex + 1, - width: disableRect.width + 'px', - height: disableRect.height + 'px', - top: disableRect.top + 'px', - left: disableRect.left + 'px' - }); - scrollMask[0].firstElementChild.style.width = scrollWidth + 'px'; - $document[0].body.appendChild(scrollMask[0]); - - scrollMask.on('wheel', preventDefault); - scrollMask.on('touchmove', preventDefault); - $document.on('keydown', disableKeyNav); - - return function restoreScroll() { - scrollMask.off('wheel'); - scrollMask.off('touchmove'); - scrollMask[0].parentNode.removeChild(scrollMask[0]); - $document.off('keydown', disableKeyNav); - }; - - // Prevent keypresses from elements inside the disableTarget - // used to stop the keypresses that could cause the page to scroll - // (arrow keys, spacebar, tab, etc). - function disableKeyNav(e) { - if (disableTarget.contains(e.target)) { - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - - function preventDefault(e) { - e.preventDefault(); - } - } - - // Converts the disableTarget (body) to a position fixed block and translate it to the propper scroll position - function disableBodyScroll() { - var restoreStyle = disableTarget.getAttribute('style') || ''; - var scrollOffset = disableTarget.scrollTop; - - applyStyles(disableTarget, { - position: 'fixed', - width: '100%', - overflowY: 'scroll', - top: -scrollOffset + 'px' - }); - - return function restoreScroll() { - disableTarget.setAttribute('style', restoreStyle); - disableTarget.scrollTop = scrollOffset; - }; - } - - function applyStyles (el, styles) { - for (var key in styles) { - el.style[key] = styles[key]; - } - } - - function isScrolling(el) { - if (el instanceof angular.element) el = el[0]; - return el.scrollHeight > el.offsetHeight; - } - }, - - floatingScrollbars: function() { - if (this.floatingScrollbars.cached === undefined) { - var tempNode = angular.element('<div style="width: 100%; z-index: -1; position: absolute; height: 35px; overflow-y: scroll"><div style="height: 60;"></div></div>'); - $document[0].body.appendChild(tempNode[0]); - this.floatingScrollbars.cached = (tempNode[0].offsetWidth == tempNode[0].childNodes[0].offsetWidth); - tempNode.remove(); - } - return this.floatingScrollbars.cached; - }, - - // Mobile safari only allows you to set focus in click event listeners... - forceFocus: function(element) { - var node = element[0] || element; - - document.addEventListener('click', function focusOnClick(ev) { - if (ev.target === node && ev.$focus) { - node.focus(); - ev.stopImmediatePropagation(); - ev.preventDefault(); - node.removeEventListener('click', focusOnClick); - } - }, true); - - var newEvent = document.createEvent('MouseEvents'); - newEvent.initMouseEvent('click', false, true, window, {}, 0, 0, 0, 0, - false, false, false, false, 0, null); - newEvent.$material = true; - newEvent.$focus = true; - node.dispatchEvent(newEvent); - }, - - transitionEndPromise: function(element, opts) { - opts = opts || {}; - var deferred = $q.defer(); - element.on($mdConstant.CSS.TRANSITIONEND, finished); - function finished(ev) { - // Make sure this transitionend didn't bubble up from a child - if (!ev || ev.target === element[0]) { - element.off($mdConstant.CSS.TRANSITIONEND, finished); - deferred.resolve(); - } - } - if (opts.timeout) $timeout(finished, opts.timeout); - return deferred.promise; - }, - - fakeNgModel: function() { - return { - $fake: true, - $setTouched: angular.noop, - $setViewValue: function(value) { - this.$viewValue = value; - this.$render(value); - this.$viewChangeListeners.forEach(function(cb) { cb(); }); - }, - $isEmpty: function(value) { - return ('' + value).length === 0; - }, - $parsers: [], - $formatters: [], - $viewChangeListeners: [], - $render: angular.noop - }; - }, - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. - // @param wait Integer value of msecs to delay (since last debounce reset); default value 10 msecs - // @param invokeApply should the $timeout trigger $digest() dirty checking - debounce: function (func, wait, scope, invokeApply) { - var timer; - - return function debounced() { - var context = scope, - args = Array.prototype.slice.call(arguments); - - $timeout.cancel(timer); - timer = $timeout(function() { - - timer = undefined; - func.apply(context, args); - - }, wait || 10, invokeApply ); - }; - }, - - // Returns a function that can only be triggered every `delay` milliseconds. - // In other words, the function will not be called unless it has been more - // than `delay` milliseconds since the last call. - throttle: function throttle(func, delay) { - var recent; - return function throttled() { - var context = this; - var args = arguments; - var now = Util.now(); - - if (!recent || (now - recent > delay)) { - func.apply(context, args); - recent = now; - } - }; - }, - - /** - * Measures the number of milliseconds taken to run the provided callback - * function. Uses a high-precision timer if available. - */ - time: function time(cb) { - var start = Util.now(); - cb(); - return Util.now() - start; - }, - - /** - * Get a unique ID. - * - * @returns {string} an unique numeric string - */ - nextUid: function() { - return '' + nextUniqueId++; - }, - - // Stop watchers and events from firing on a scope without destroying it, - // by disconnecting it from its parent and its siblings' linked lists. - disconnectScope: function disconnectScope(scope) { - if (!scope) return; - - // we can't destroy the root scope or a scope that has been already destroyed - if (scope.$root === scope) return; - if (scope.$$destroyed ) return; - - var parent = scope.$parent; - scope.$$disconnected = true; - - // See Scope.$destroy - if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling; - if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling; - if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling; - if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling; - - scope.$$nextSibling = scope.$$prevSibling = null; - - }, - - // Undo the effects of disconnectScope above. - reconnectScope: function reconnectScope(scope) { - if (!scope) return; - - // we can't disconnect the root node or scope already disconnected - if (scope.$root === scope) return; - if (!scope.$$disconnected) return; - - var child = scope; - - var parent = child.$parent; - child.$$disconnected = false; - // See Scope.$new for this logic... - child.$$prevSibling = parent.$$childTail; - if (parent.$$childHead) { - parent.$$childTail.$$nextSibling = child; - parent.$$childTail = child; - } else { - parent.$$childHead = parent.$$childTail = child; - } - }, - - /* - * getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching nodeName - * - * @param el Element to start walking the DOM from - * @param tagName Tag name to find closest to el, such as 'form' - */ - getClosest: function getClosest(el, tagName, onlyParent) { - if (el instanceof angular.element) el = el[0]; - tagName = tagName.toUpperCase(); - if (onlyParent) el = el.parentNode; - if (!el) return null; - do { - if (el.nodeName === tagName) { - return el; - } - } while (el = el.parentNode); - return null; - }, - - /** - * Functional equivalent for $element.filter(‘md-bottom-sheet’) - * useful with interimElements where the element and its container are important... - */ - extractElementByName: function (element, nodeName) { - for (var i = 0, len = element.length; i < len; i++) { - if (element[i].nodeName.toLowerCase() === nodeName){ - return angular.element(element[i]); - } - } - return element; - }, - - /** - * Give optional properties with no value a boolean true by default - */ - initOptionalProperties: function (scope, attr, defaults ) { - defaults = defaults || { }; - angular.forEach(scope.$$isolateBindings, function (binding, key) { - if (binding.optional && angular.isUndefined(scope[key])) { - var hasKey = attr.hasOwnProperty(attr.$normalize(binding.attrName)); - - scope[key] = angular.isDefined(defaults[key]) ? defaults[key] : hasKey; - } - }); - } - - }; - -}]); - -/* - * Since removing jQuery from the demos, some code that uses `element.focus()` is broken. - * - * We need to add `element.focus()`, because it's testable unlike `element[0].focus`. - * - * TODO(ajoslin): This should be added in a better place later. - */ - -angular.element.prototype.focus = angular.element.prototype.focus || function() { - if (this.length) { - this[0].focus(); - } - return this; -}; -angular.element.prototype.blur = angular.element.prototype.blur || function() { - if (this.length) { - this[0].blur(); - } - return this; -}; - - -angular.module('material.core') - .service('$mdAria', AriaService); - -/* - * ngInject - */ -function AriaService($$rAF, $log, $window) { - - return { - expect: expect, - expectAsync: expectAsync, - expectWithText: expectWithText - }; - - /** - * 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 = 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 { - $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) { - expectAsync(element, attrName, function() { - return getText(element); - }); - } - - function getText(element) { - return element.text().trim(); - } - - 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; - } -} -AriaService.$inject = ["$$rAF", "$log", "$window"]; - -angular.module('material.core') - .service('$mdCompiler', mdCompilerService); - -function mdCompilerService($q, $http, $injector, $compile, $controller, $templateCache) { - /* jshint validthis: true */ - - /* - * @ngdoc service - * @name $mdCompiler - * @module material.core - * @description - * The $mdCompiler service is an abstraction of angular's compiler, that allows the developer - * to easily compile an element with a templateUrl, controller, and locals. - * - * @usage - * <hljs lang="js"> - * $mdCompiler.compile({ - * templateUrl: 'modal.html', - * controller: 'ModalCtrl', - * locals: { - * modal: myModalInstance; - * } - * }).then(function(compileData) { - * compileData.element; // modal.html's template in an element - * compileData.link(myScope); //attach controller & scope to element - * }); - * </hljs> - */ - - /* - * @ngdoc method - * @name $mdCompiler#compile - * @description A helper to compile an HTML template/templateUrl with a given controller, - * locals, and scope. - * @param {object} options An options object, with the following properties: - * - * - `controller` - `{(string=|function()=}` Controller fn that should be associated with - * newly created scope or the name of a registered controller if passed as a string. - * - `controllerAs` - `{string=}` A controller alias name. If present the controller will be - * published to scope under the `controllerAs` name. - * - `template` - `{string=}` An html template as a string. - * - `templateUrl` - `{string=}` A path to an html template. - * - `transformTemplate` - `{function(template)=}` A function which transforms the template after - * it is loaded. It will be given the template string as a parameter, and should - * return a a new string representing the transformed template. - * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should - * be injected into the controller. If any of these dependencies are promises, the compiler - * will wait for them all to be resolved, or if one is rejected before the controller is - * instantiated `compile()` will fail.. - * * `key` - `{string}`: a name of a dependency to be injected into the controller. - * * `factory` - `{string|function}`: If `string` then it is an alias for a service. - * Otherwise if function, then it is injected and the return value is treated as the - * dependency. If the result is a promise, it is resolved before its value is - * injected into the controller. - * - * @returns {object=} promise A promise, which will be resolved with a `compileData` object. - * `compileData` has the following properties: - * - * - `element` - `{element}`: an uncompiled element matching the provided template. - * - `link` - `{function(scope)}`: A link function, which, when called, will compile - * the element and instantiate the provided controller (if given). - * - `locals` - `{object}`: The locals which will be passed into the controller once `link` is - * called. If `bindToController` is true, they will be coppied to the ctrl instead - * - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in. - */ - this.compile = function(options) { - var templateUrl = options.templateUrl; - var template = options.template || ''; - var controller = options.controller; - var controllerAs = options.controllerAs; - var resolve = options.resolve || {}; - var locals = options.locals || {}; - var transformTemplate = options.transformTemplate || angular.identity; - var bindToController = options.bindToController; - - // Take resolve values and invoke them. - // Resolves can either be a string (value: 'MyRegisteredAngularConst'), - // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {}) - angular.forEach(resolve, function(value, key) { - if (angular.isString(value)) { - resolve[key] = $injector.get(value); - } else { - resolve[key] = $injector.invoke(value); - } - }); - //Add the locals, which are just straight values to inject - //eg locals: { three: 3 }, will inject three into the controller - angular.extend(resolve, locals); - - if (templateUrl) { - resolve.$template = $http.get(templateUrl, {cache: $templateCache}) - .then(function(response) { - return response.data; - }); - } else { - resolve.$template = $q.when(template); - } - - // Wait for all the resolves to finish if they are promises - return $q.all(resolve).then(function(locals) { - - var template = transformTemplate(locals.$template); - var element = options.element || angular.element('<div>').html(template.trim()).contents(); - var linkFn = $compile(element); - - //Return a linking function that can be used later when the element is ready - return { - locals: locals, - element: element, - link: function link(scope) { - locals.$scope = scope; - - //Instantiate controller if it exists, because we have scope - if (controller) { - var invokeCtrl = $controller(controller, locals, true); - if (bindToController) { - angular.extend(invokeCtrl.instance, locals); - } - var ctrl = invokeCtrl(); - //See angular-route source for this logic - element.data('$ngControllerController', ctrl); - element.children().data('$ngControllerController', ctrl); - - if (controllerAs) { - scope[controllerAs] = ctrl; - } - } - return linkFn(scope); - } - }; - }); - - }; -} -mdCompilerService.$inject = ["$q", "$http", "$injector", "$compile", "$controller", "$templateCache"]; - - var HANDLERS = {}; - /* The state of the current 'pointer' - * The pointer represents the state of the current touch. - * It contains normalized x and y coordinates from DOM events, - * as well as other information abstracted from the DOM. - */ - var pointer, lastPointer, forceSkipClickHijack = false; - - // Used to attach event listeners once when multiple ng-apps are running. - var isInitialized = false; - - angular - .module('material.core.gestures', [ ]) - .provider('$mdGesture', MdGestureProvider) - .factory('$$MdGestureHandler', MdGestureHandler) - .run( attachToDocument ); - - /** - * @ngdoc service - * @name $mdGestureProvider - * @module material.core.gestures - * - * @description - * In some scenarios on Mobile devices (without jQuery), the click events should NOT be hijacked. - * `$mdGestureProvider` is used to configure the Gesture module to ignore or skip click hijacking on mobile - * devices. - * - * <hljs lang="js"> - * app.config(function($mdGestureProvider) { - * - * // For mobile devices without jQuery loaded, do not - * // intercept click events during the capture phase. - * $mdGestureProvider.skipClickHijack(); - * - * }); - * </hljs> - * - */ - function MdGestureProvider() { } - - MdGestureProvider.prototype = { - - // Publish access to setter to configure a variable BEFORE the - // $mdGesture service is instantiated... - skipClickHijack: function() { - return forceSkipClickHijack = true; - }, - - /** - * $get is used to build an instance of $mdGesture - * ngInject - */ - $get : ["$$MdGestureHandler", "$$rAF", "$timeout", function($$MdGestureHandler, $$rAF, $timeout) { - return new MdGesture($$MdGestureHandler, $$rAF, $timeout); - }] - }; - - - - /** - * MdGesture factory construction function - * ngInject - */ - function MdGesture($$MdGestureHandler, $$rAF, $timeout) { - var userAgent = navigator.userAgent || navigator.vendor || window.opera; - var isIos = userAgent.match(/ipad|iphone|ipod/i); - var isAndroid = userAgent.match(/android/i); - var hasJQuery = (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery); - - var self = { - handler: addHandler, - register: register, - // On mobile w/out jQuery, we normally intercept clicks. Should we skip that? - isHijackingClicks: (isIos || isAndroid) && !hasJQuery && !forceSkipClickHijack - }; - - if (self.isHijackingClicks) { - self.handler('click', { - options: { - maxDistance: 6 - }, - onEnd: function (ev, pointer) { - if (pointer.distance < this.state.options.maxDistance) { - this.dispatchEvent(ev, 'click'); - } - } - }); - } - - /* - * Register an element to listen for a handler. - * This allows an element to override the default options for a handler. - * Additionally, some handlers like drag and hold only dispatch events if - * the domEvent happens inside an element that's registered to listen for these events. - * - * @see GestureHandler for how overriding of default options works. - * @example $mdGesture.register(myElement, 'drag', { minDistance: 20, horziontal: false }) - */ - function register(element, handlerName, options) { - var handler = HANDLERS[handlerName.replace(/^\$md./, '')]; - if (!handler) { - throw new Error('Failed to register element with handler ' + handlerName + '. ' + - 'Available handlers: ' + Object.keys(HANDLERS).join(', ')); - } - return handler.registerElement(element, options); - } - - /* - * add a handler to $mdGesture. see below. - */ - function addHandler(name, definition) { - var handler = new $$MdGestureHandler(name); - angular.extend(handler, definition); - HANDLERS[name] = handler; - - return self; - } - - /* - * Register handlers. These listen to touch/start/move events, interpret them, - * and dispatch gesture events depending on options & conditions. These are all - * instances of GestureHandler. - * @see GestureHandler - */ - return self - /* - * The press handler dispatches an event on touchdown/touchend. - * It's a simple abstraction of touch/mouse/pointer start and end. - */ - .handler('press', { - onStart: function (ev, pointer) { - this.dispatchEvent(ev, '$md.pressdown'); - }, - onEnd: function (ev, pointer) { - this.dispatchEvent(ev, '$md.pressup'); - } - }) - - /* - * The hold handler dispatches an event if the user keeps their finger within - * the same <maxDistance> area for <delay> ms. - * The hold handler will only run if a parent of the touch target is registered - * to listen for hold events through $mdGesture.register() - */ - .handler('hold', { - options: { - maxDistance: 6, - delay: 500 - }, - onCancel: function () { - $timeout.cancel(this.state.timeout); - }, - onStart: function (ev, pointer) { - // For hold, require a parent to be registered with $mdGesture.register() - // Because we prevent scroll events, this is necessary. - if (!this.state.registeredParent) return this.cancel(); - - this.state.pos = {x: pointer.x, y: pointer.y}; - this.state.timeout = $timeout(angular.bind(this, function holdDelayFn() { - this.dispatchEvent(ev, '$md.hold'); - this.cancel(); //we're done! - }), this.state.options.delay, false); - }, - onMove: function (ev, pointer) { - // Don't scroll while waiting for hold. - // If we don't preventDefault touchmove events here, Android will assume we don't - // want to listen to anymore touch events. It will start scrolling and stop sending - // touchmove events. - ev.preventDefault(); - - // If the user moves greater than <maxDistance> pixels, stop the hold timer - // set in onStart - var dx = this.state.pos.x - pointer.x; - var dy = this.state.pos.y - pointer.y; - if (Math.sqrt(dx * dx + dy * dy) > this.options.maxDistance) { - this.cancel(); - } - }, - onEnd: function () { - this.onCancel(); - } - }) - - /* - * The drag handler dispatches a drag event if the user holds and moves his finger greater than - * <minDistance> px in the x or y direction, depending on options.horizontal. - * The drag will be cancelled if the user moves his finger greater than <minDistance>*<cancelMultiplier> in - * the perpindicular direction. Eg if the drag is horizontal and the user moves his finger <minDistance>*<cancelMultiplier> - * pixels vertically, this handler won't consider the move part of a drag. - */ - .handler('drag', { - options: { - minDistance: 6, - horizontal: true, - cancelMultiplier: 1.5 - }, - onStart: function (ev) { - // For drag, require a parent to be registered with $mdGesture.register() - if (!this.state.registeredParent) this.cancel(); - }, - onMove: function (ev, pointer) { - var shouldStartDrag, shouldCancel; - // Don't scroll while deciding if this touchmove qualifies as a drag event. - // If we don't preventDefault touchmove events here, Android will assume we don't - // want to listen to anymore touch events. It will start scrolling and stop sending - // touchmove events. - ev.preventDefault(); - - if (!this.state.dragPointer) { - if (this.state.options.horizontal) { - shouldStartDrag = Math.abs(pointer.distanceX) > this.state.options.minDistance; - shouldCancel = Math.abs(pointer.distanceY) > this.state.options.minDistance * this.state.options.cancelMultiplier; - } else { - shouldStartDrag = Math.abs(pointer.distanceY) > this.state.options.minDistance; - shouldCancel = Math.abs(pointer.distanceX) > this.state.options.minDistance * this.state.options.cancelMultiplier; - } - - if (shouldStartDrag) { - // Create a new pointer representing this drag, starting at this point where the drag started. - this.state.dragPointer = makeStartPointer(ev); - updatePointerState(ev, this.state.dragPointer); - this.dispatchEvent(ev, '$md.dragstart', this.state.dragPointer); - - } else if (shouldCancel) { - this.cancel(); - } - } else { - this.dispatchDragMove(ev); - } - }, - // Only dispatch dragmove events every frame; any more is unnecessray - dispatchDragMove: $$rAF.throttle(function (ev) { - // Make sure the drag didn't stop while waiting for the next frame - if (this.state.isRunning) { - updatePointerState(ev, this.state.dragPointer); - this.dispatchEvent(ev, '$md.drag', this.state.dragPointer); - } - }), - onEnd: function (ev, pointer) { - if (this.state.dragPointer) { - updatePointerState(ev, this.state.dragPointer); - this.dispatchEvent(ev, '$md.dragend', this.state.dragPointer); - } - } - }) - - /* - * The swipe handler will dispatch a swipe event if, on the end of a touch, - * the velocity and distance were high enough. - * TODO: add vertical swiping with a `horizontal` option similar to the drag handler. - */ - .handler('swipe', { - options: { - minVelocity: 0.65, - minDistance: 10 - }, - onEnd: function (ev, pointer) { - if (Math.abs(pointer.velocityX) > this.state.options.minVelocity && - Math.abs(pointer.distanceX) > this.state.options.minDistance) { - var eventType = pointer.directionX == 'left' ? '$md.swipeleft' : '$md.swiperight'; - this.dispatchEvent(ev, eventType); - } - } - }); - - } - MdGesture.$inject = ["$$MdGestureHandler", "$$rAF", "$timeout"]; - - /** - * MdGestureHandler - * A GestureHandler is an object which is able to dispatch custom dom events - * based on native dom {touch,pointer,mouse}{start,move,end} events. - * - * A gesture will manage its lifecycle through the start,move,end, and cancel - * functions, which are called by native dom events. - * - * A gesture has the concept of 'options' (eg a swipe's required velocity), which can be - * overridden by elements registering through $mdGesture.register() - */ - function GestureHandler (name) { - this.name = name; - this.state = {}; - } - - function MdGestureHandler() { - var hasJQuery = (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery); - - GestureHandler.prototype = { - options: {}, - // jQuery listeners don't work with custom DOMEvents, so we have to dispatch events - // differently when jQuery is loaded - dispatchEvent: hasJQuery ? jQueryDispatchEvent : nativeDispatchEvent, - - // These are overridden by the registered handler - onStart: angular.noop, - onMove: angular.noop, - onEnd: angular.noop, - onCancel: angular.noop, - - // onStart sets up a new state for the handler, which includes options from the - // nearest registered parent element of ev.target. - start: function (ev, pointer) { - if (this.state.isRunning) return; - var parentTarget = this.getNearestParent(ev.target); - // Get the options from the nearest registered parent - var parentTargetOptions = parentTarget && parentTarget.$mdGesture[this.name] || {}; - - this.state = { - isRunning: true, - // Override the default options with the nearest registered parent's options - options: angular.extend({}, this.options, parentTargetOptions), - // Pass in the registered parent node to the state so the onStart listener can use - registeredParent: parentTarget - }; - this.onStart(ev, pointer); - }, - move: function (ev, pointer) { - if (!this.state.isRunning) return; - this.onMove(ev, pointer); - }, - end: function (ev, pointer) { - if (!this.state.isRunning) return; - this.onEnd(ev, pointer); - this.state.isRunning = false; - }, - cancel: function (ev, pointer) { - this.onCancel(ev, pointer); - this.state = {}; - }, - - // Find and return the nearest parent element that has been registered to - // listen for this handler via $mdGesture.register(element, 'handlerName'). - getNearestParent: function (node) { - var current = node; - while (current) { - if ((current.$mdGesture || {})[this.name]) { - return current; - } - current = current.parentNode; - } - return null; - }, - - // Called from $mdGesture.register when an element reigsters itself with a handler. - // Store the options the user gave on the DOMElement itself. These options will - // be retrieved with getNearestParent when the handler starts. - registerElement: function (element, options) { - var self = this; - element[0].$mdGesture = element[0].$mdGesture || {}; - element[0].$mdGesture[this.name] = options || {}; - element.on('$destroy', onDestroy); - - return onDestroy; - - function onDestroy() { - delete element[0].$mdGesture[self.name]; - element.off('$destroy', onDestroy); - } - } - }; - - return GestureHandler; - - /* - * Dispatch an event with jQuery - * TODO: Make sure this sends bubbling events - * - * @param srcEvent the original DOM touch event that started this. - * @param eventType the name of the custom event to send (eg 'click' or '$md.drag') - * @param eventPointer the pointer object that matches this event. - */ - function jQueryDispatchEvent(srcEvent, eventType, eventPointer) { - eventPointer = eventPointer || pointer; - var eventObj = new angular.element.Event(eventType); - - eventObj.$material = true; - eventObj.pointer = eventPointer; - eventObj.srcEvent = srcEvent; - - angular.extend(eventObj, { - clientX: eventPointer.x, - clientY: eventPointer.y, - screenX: eventPointer.x, - screenY: eventPointer.y, - pageX: eventPointer.x, - pageY: eventPointer.y, - ctrlKey: srcEvent.ctrlKey, - altKey: srcEvent.altKey, - shiftKey: srcEvent.shiftKey, - metaKey: srcEvent.metaKey - }); - angular.element(eventPointer.target).trigger(eventObj); - } - - /* - * NOTE: nativeDispatchEvent is very performance sensitive. - * @param srcEvent the original DOM touch event that started this. - * @param eventType the name of the custom event to send (eg 'click' or '$md.drag') - * @param eventPointer the pointer object that matches this event. - */ - function nativeDispatchEvent(srcEvent, eventType, eventPointer) { - eventPointer = eventPointer || pointer; - var eventObj; - - if (eventType === 'click') { - eventObj = document.createEvent('MouseEvents'); - eventObj.initMouseEvent( - 'click', true, true, window, srcEvent.detail, - eventPointer.x, eventPointer.y, eventPointer.x, eventPointer.y, - srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey, - srcEvent.button, srcEvent.relatedTarget || null - ); - - } else { - eventObj = document.createEvent('CustomEvent'); - eventObj.initCustomEvent(eventType, true, true, {}); - } - eventObj.$material = true; - eventObj.pointer = eventPointer; - eventObj.srcEvent = srcEvent; - eventPointer.target.dispatchEvent(eventObj); - } - - } - - /** - * Attach Gestures: hook document and check shouldHijack clicks - * ngInject - */ - function attachToDocument( $mdGesture, $$MdGestureHandler ) { - - // Polyfill document.contains for IE11. - // TODO: move to util - document.contains || (document.contains = function (node) { - return document.body.contains(node); - }); - - if (!isInitialized && $mdGesture.isHijackingClicks ) { - /* - * If hijack clicks is true, we preventDefault any click that wasn't - * sent by ngMaterial. This is because on older Android & iOS, a false, or 'ghost', - * click event will be sent ~400ms after a touchend event happens. - * The only way to know if this click is real is to prevent any normal - * click events, and add a flag to events sent by material so we know not to prevent those. - * - * Two exceptions to click events that should be prevented are: - * - click events sent by the keyboard (eg form submit) - * - events that originate from an Ionic app - */ - document.addEventListener('click', function clickHijacker(ev) { - var isKeyClick = ev.clientX === 0 && ev.clientY === 0; - if (!isKeyClick && !ev.$material && !ev.isIonicTap) { - ev.preventDefault(); - ev.stopPropagation(); - } - }, true); - - isInitialized = true; - } - - // Listen to all events to cover all platforms. - var START_EVENTS = 'mousedown touchstart pointerdown'; - var MOVE_EVENTS = 'mousemove touchmove pointermove'; - var END_EVENTS = 'mouseup mouseleave touchend touchcancel pointerup pointercancel'; - - angular.element(document) - .on(START_EVENTS, gestureStart) - .on(MOVE_EVENTS, gestureMove) - .on(END_EVENTS, gestureEnd) - // For testing - .on('$$mdGestureReset', function gestureClearCache () { - lastPointer = pointer = null; - }); - - /* - * When a DOM event happens, run all registered gesture handlers' lifecycle - * methods which match the DOM event. - * Eg when a 'touchstart' event happens, runHandlers('start') will call and - * run `handler.cancel()` and `handler.start()` on all registered handlers. - */ - function runHandlers(handlerEvent, event) { - var handler; - for (var name in HANDLERS) { - handler = HANDLERS[name]; - if( handler instanceof $$MdGestureHandler ) { - - if (handlerEvent === 'start') { - // Run cancel to reset any handlers' state - handler.cancel(); - } - handler[handlerEvent](event, pointer); - - } - } - } - - /* - * gestureStart vets if a start event is legitimate (and not part of a 'ghost click' from iOS/Android) - * If it is legitimate, we initiate the pointer state and mark the current pointer's type - * For example, for a touchstart event, mark the current pointer as a 'touch' pointer, so mouse events - * won't effect it. - */ - function gestureStart(ev) { - // If we're already touched down, abort - if (pointer) return; - - var now = +Date.now(); - - // iOS & old android bug: after a touch event, a click event is sent 350 ms later. - // If <400ms have passed, don't allow an event of a different type than the previous event - if (lastPointer && !typesMatch(ev, lastPointer) && (now - lastPointer.endTime < 1500)) { - return; - } - - pointer = makeStartPointer(ev); - - runHandlers('start', ev); - } - /* - * If a move event happens of the right type, update the pointer and run all the move handlers. - * "of the right type": if a mousemove happens but our pointer started with a touch event, do nothing. - */ - function gestureMove(ev) { - if (!pointer || !typesMatch(ev, pointer)) return; - - updatePointerState(ev, pointer); - runHandlers('move', ev); - } - /* - * If an end event happens of the right type, update the pointer, run endHandlers, and save the pointer as 'lastPointer' - */ - function gestureEnd(ev) { - if (!pointer || !typesMatch(ev, pointer)) return; - - updatePointerState(ev, pointer); - pointer.endTime = +Date.now(); - - runHandlers('end', ev); - - lastPointer = pointer; - pointer = null; - } - - } - attachToDocument.$inject = ["$mdGesture", "$$MdGestureHandler"]; - - // ******************** - // Module Functions - // ******************** - - /* - * Initiate the pointer. x, y, and the pointer's type. - */ - function makeStartPointer(ev) { - var point = getEventPoint(ev); - var startPointer = { - startTime: +Date.now(), - target: ev.target, - // 'p' for pointer events, 'm' for mouse, 't' for touch - type: ev.type.charAt(0) - }; - startPointer.startX = startPointer.x = point.pageX; - startPointer.startY = startPointer.y = point.pageY; - return startPointer; - } - - /* - * return whether the pointer's type matches the event's type. - * Eg if a touch event happens but the pointer has a mouse type, return false. - */ - function typesMatch(ev, pointer) { - return ev && pointer && ev.type.charAt(0) === pointer.type; - } - - /* - * Update the given pointer based upon the given DOMEvent. - * Distance, velocity, direction, duration, etc - */ - function updatePointerState(ev, pointer) { - var point = getEventPoint(ev); - var x = pointer.x = point.pageX; - var y = pointer.y = point.pageY; - - pointer.distanceX = x - pointer.startX; - pointer.distanceY = y - pointer.startY; - pointer.distance = Math.sqrt( - pointer.distanceX * pointer.distanceX + pointer.distanceY * pointer.distanceY - ); - - pointer.directionX = pointer.distanceX > 0 ? 'right' : pointer.distanceX < 0 ? 'left' : ''; - pointer.directionY = pointer.distanceY > 0 ? 'up' : pointer.distanceY < 0 ? 'down' : ''; - - pointer.duration = +Date.now() - pointer.startTime; - pointer.velocityX = pointer.distanceX / pointer.duration; - pointer.velocityY = pointer.distanceY / pointer.duration; - } - - /* - * Normalize the point where the DOM event happened whether it's touch or mouse. - * @returns point event obj with pageX and pageY on it. - */ - function getEventPoint(ev) { - ev = ev.originalEvent || ev; // support jQuery events - return (ev.touches && ev.touches[0]) || - (ev.changedTouches && ev.changedTouches[0]) || - ev; - } - -angular.module('material.core') - .provider('$$interimElement', InterimElementProvider); - -/* - * @ngdoc service - * @name $$interimElement - * @module material.core - * - * @description - * - * Factory that contructs `$$interimElement.$service` services. - * Used internally in material design for elements that appear on screen temporarily. - * The service provides a promise-like API for interacting with the temporary - * elements. - * - * ```js - * app.service('$mdToast', function($$interimElement) { - * var $mdToast = $$interimElement(toastDefaultOptions); - * return $mdToast; - * }); - * ``` - * @param {object=} defaultOptions Options used by default for the `show` method on the service. - * - * @returns {$$interimElement.$service} - * - */ - -function InterimElementProvider() { - createInterimElementProvider.$get = InterimElementFactory; - InterimElementFactory.$inject = ["$document", "$q", "$rootScope", "$timeout", "$rootElement", "$animate", "$interpolate", "$mdCompiler", "$mdTheming"]; - return createInterimElementProvider; - - /** - * Returns a new provider which allows configuration of a new interimElement - * service. Allows configuration of default options & methods for options, - * as well as configuration of 'preset' methods (eg dialog.basic(): basic is a preset method) - */ - function createInterimElementProvider(interimFactoryName) { - var EXPOSED_METHODS = ['onHide', 'onShow', 'onRemove']; - - var customMethods = {}; - var providerConfig = { - presets: {} - }; - - var provider = { - setDefaults: setDefaults, - addPreset: addPreset, - addMethod: addMethod, - $get: factory - }; - - /** - * all interim elements will come with the 'build' preset - */ - provider.addPreset('build', { - methods: ['controller', 'controllerAs', 'resolve', - 'template', 'templateUrl', 'themable', 'transformTemplate', 'parent'] - }); - - factory.$inject = ["$$interimElement", "$animate", "$injector"]; - return provider; - - /** - * Save the configured defaults to be used when the factory is instantiated - */ - function setDefaults(definition) { - providerConfig.optionsFactory = definition.options; - providerConfig.methods = (definition.methods || []).concat(EXPOSED_METHODS); - return provider; - } - - /** - * Add a method to the factory that isn't specific to any interim element operations - */ - - function addMethod(name, fn) { - customMethods[name] = fn; - return provider; - } - - /** - * Save the configured preset to be used when the factory is instantiated - */ - function addPreset(name, definition) { - definition = definition || {}; - definition.methods = definition.methods || []; - definition.options = definition.options || function() { return {}; }; - - if (/^cancel|hide|show$/.test(name)) { - throw new Error("Preset '" + name + "' in " + interimFactoryName + " is reserved!"); - } - if (definition.methods.indexOf('_options') > -1) { - throw new Error("Method '_options' in " + interimFactoryName + " is reserved!"); - } - providerConfig.presets[name] = { - methods: definition.methods.concat(EXPOSED_METHODS), - optionsFactory: definition.options, - argOption: definition.argOption - }; - return provider; - } - - /** - * Create a factory that has the given methods & defaults implementing interimElement - */ - /* ngInject */ - function factory($$interimElement, $animate, $injector) { - var defaultMethods; - var defaultOptions; - var interimElementService = $$interimElement(); - - /* - * publicService is what the developer will be using. - * It has methods hide(), cancel(), show(), build(), and any other - * presets which were set during the config phase. - */ - var publicService = { - hide: interimElementService.hide, - cancel: interimElementService.cancel, - show: showInterimElement - }; - - defaultMethods = providerConfig.methods || []; - // This must be invoked after the publicService is initialized - defaultOptions = invokeFactory(providerConfig.optionsFactory, {}); - - // Copy over the simple custom methods - angular.forEach(customMethods, function(fn, name) { - publicService[name] = fn; - }); - - angular.forEach(providerConfig.presets, function(definition, name) { - var presetDefaults = invokeFactory(definition.optionsFactory, {}); - var presetMethods = (definition.methods || []).concat(defaultMethods); - - // Every interimElement built with a preset has a field called `$type`, - // which matches the name of the preset. - // Eg in preset 'confirm', options.$type === 'confirm' - angular.extend(presetDefaults, { $type: name }); - - // This creates a preset class which has setter methods for every - // method given in the `.addPreset()` function, as well as every - // method given in the `.setDefaults()` function. - // - // @example - // .setDefaults({ - // methods: ['hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent'], - // options: dialogDefaultOptions - // }) - // .addPreset('alert', { - // methods: ['title', 'ok'], - // options: alertDialogOptions - // }) - // - // Set values will be passed to the options when interimElemnt.show() is called. - function Preset(opts) { - this._options = angular.extend({}, presetDefaults, opts); - } - angular.forEach(presetMethods, function(name) { - Preset.prototype[name] = function(value) { - this._options[name] = value; - return this; - }; - }); - - // Create shortcut method for one-linear methods - if (definition.argOption) { - var methodName = 'show' + name.charAt(0).toUpperCase() + name.slice(1); - publicService[methodName] = function(arg) { - var config = publicService[name](arg); - return publicService.show(config); - }; - } - - // eg $mdDialog.alert() will return a new alert preset - publicService[name] = function(arg) { - // If argOption is supplied, eg `argOption: 'content'`, then we assume - // if the argument is not an options object then it is the `argOption` option. - // - // @example `$mdToast.simple('hello')` // sets options.content to hello - // // because argOption === 'content' - if (arguments.length && definition.argOption && !angular.isObject(arg) && - !angular.isArray(arg)) { - return (new Preset())[definition.argOption](arg); - } else { - return new Preset(arg); - } - - }; - }); - - return publicService; - - function showInterimElement(opts) { - // opts is either a preset which stores its options on an _options field, - // or just an object made up of options - if (opts && opts._options) opts = opts._options; - return interimElementService.show( - angular.extend({}, defaultOptions, opts) - ); - } - - /** - * Helper to call $injector.invoke with a local of the factory name for - * this provider. - * If an $mdDialog is providing options for a dialog and tries to inject - * $mdDialog, a circular dependency error will happen. - * We get around that by manually injecting $mdDialog as a local. - */ - function invokeFactory(factory, defaultVal) { - var locals = {}; - locals[interimFactoryName] = publicService; - return $injector.invoke(factory || function() { return defaultVal; }, {}, locals); - } - - } - - } - - /* ngInject */ - function InterimElementFactory($document, $q, $rootScope, $timeout, $rootElement, $animate, - $interpolate, $mdCompiler, $mdTheming ) { - var startSymbol = $interpolate.startSymbol(), - endSymbol = $interpolate.endSymbol(), - usesStandardSymbols = ((startSymbol === '{{') && (endSymbol === '}}')), - processTemplate = usesStandardSymbols ? angular.identity : replaceInterpolationSymbols; - - return function createInterimElementService() { - /* - * @ngdoc service - * @name $$interimElement.$service - * - * @description - * A service used to control inserting and removing an element into the DOM. - * - */ - var stack = []; - var service; - return service = { - show: show, - hide: hide, - cancel: cancel - }; - - /* - * @ngdoc method - * @name $$interimElement.$service#show - * @kind function - * - * @description - * Adds the `$interimElement` to the DOM and returns a promise that will be resolved or rejected - * with hide or cancel, respectively. - * - * @param {*} options is hashMap of settings - * @returns a Promise - * - */ - function show(options) { - if (stack.length) { - return service.cancel().then(function() { - return show(options); - }); - } else { - var interimElement = new InterimElement(options); - stack.push(interimElement); - return interimElement.show().then(function() { - return interimElement.deferred.promise; - }); - } - } - - /* - * @ngdoc method - * @name $$interimElement.$service#hide - * @kind function - * - * @description - * Removes the `$interimElement` from the DOM and resolves the promise returned from `show` - * - * @param {*} resolveParam Data to resolve the promise with - * @returns a Promise that will be resolved after the element has been removed. - * - */ - function hide(response) { - var interimElement = stack.shift(); - return interimElement && interimElement.remove().then(function() { - interimElement.deferred.resolve(response); - }); - } - - /* - * @ngdoc method - * @name $$interimElement.$service#cancel - * @kind function - * - * @description - * Removes the `$interimElement` from the DOM and rejects the promise returned from `show` - * - * @param {*} reason Data to reject the promise with - * @returns Promise that will be resolved after the element has been removed. - * - */ - function cancel(reason) { - var interimElement = stack.shift(); - return $q.when(interimElement && interimElement.remove().then(function() { - interimElement.deferred.reject(reason); - })); - } - - - /* - * Internal Interim Element Object - * Used internally to manage the DOM element and related data - */ - function InterimElement(options) { - var self; - var hideTimeout, element, showDone, removeDone; - - options = options || {}; - options = angular.extend({ - preserveScope: false, - scope: options.scope || $rootScope.$new(options.isolateScope), - onShow: function(scope, element, options) { - return $animate.enter(element, options.parent); - }, - onRemove: function(scope, element, options) { - // Element could be undefined if a new element is shown before - // the old one finishes compiling. - return element && $animate.leave(element) || $q.when(); - } - }, options); - - if (options.template) { - options.template = processTemplate(options.template); - } - - return self = { - options: options, - deferred: $q.defer(), - show: function() { - var compilePromise; - if (options.skipCompile) { - compilePromise = $q(function(resolve) { - resolve({ - locals: {}, - link: function() { return options.element; } - }); - }); - } else { - compilePromise = $mdCompiler.compile(options); - } - - return showDone = compilePromise.then(function(compileData) { - angular.extend(compileData.locals, self.options); - - element = compileData.link(options.scope); - - // Search for parent at insertion time, if not specified - if (angular.isFunction(options.parent)) { - options.parent = options.parent(options.scope, element, options); - } else if (angular.isString(options.parent)) { - options.parent = angular.element($document[0].querySelector(options.parent)); - } - - // If parent querySelector/getter function fails, or it's just null, - // find a default. - if (!(options.parent || {}).length) { - var el; - if ($rootElement[0] && $rootElement[0].querySelector) { - el = $rootElement[0].querySelector(':not(svg) > body'); - } - if (!el) el = $rootElement[0]; - if (el.nodeName == '#comment') { - el = $document[0].body; - } - options.parent = angular.element(el); - } - - if (options.themable) $mdTheming(element); - var ret = options.onShow(options.scope, element, options); - return $q.when(ret) - .then(function(){ - // Issue onComplete callback when the `show()` finishes - (options.onComplete || angular.noop)(options.scope, element, options); - startHideTimeout(); - }); - - function startHideTimeout() { - if (options.hideDelay) { - hideTimeout = $timeout(service.cancel, options.hideDelay) ; - } - } - }, function(reason) { showDone = true; self.deferred.reject(reason); }); - }, - cancelTimeout: function() { - if (hideTimeout) { - $timeout.cancel(hideTimeout); - hideTimeout = undefined; - } - }, - remove: function() { - self.cancelTimeout(); - return removeDone = $q.when(showDone).then(function() { - var ret = element ? options.onRemove(options.scope, element, options) : true; - return $q.when(ret).then(function() { - if (!options.preserveScope) options.scope.$destroy(); - removeDone = true; - }); - }); - } - }; - } - }; - - /* - * Replace `{{` and `}}` in a string (usually a template) with the actual start-/endSymbols used - * for interpolation. This allows pre-defined templates (for components such as dialog, toast etc) - * to continue to work in apps that use custom interpolation start-/endSymbols. - * - * @param {string} text The text in which to replace `{{` / `}}` - * @returns {string} The modified string using the actual interpolation start-/endSymbols - */ - function replaceInterpolationSymbols(text) { - if (!text || !angular.isString(text)) return text; - return text.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); - } - } - -} - - /** - * @ngdoc module - * @name material.core.componentRegistry - * - * @description - * A component instance registration service. - * Note: currently this as a private service in the SideNav component. - */ - angular.module('material.core') - .factory('$mdComponentRegistry', ComponentRegistry); - - /* - * @private - * @ngdoc factory - * @name ComponentRegistry - * @module material.core.componentRegistry - * - */ - function ComponentRegistry($log, $q) { - - var self; - var instances = [ ]; - var pendings = { }; - - return self = { - /** - * Used to print an error when an instance for a handle isn't found. - */ - notFoundError: function(handle) { - $log.error('No instance found for handle', handle); - }, - /** - * Return all registered instances as an array. - */ - getInstances: function() { - return instances; - }, - - /** - * Get a registered instance. - * @param handle the String handle to look up for a registered instance. - */ - get: function(handle) { - if ( !isValidID(handle) ) return null; - - var i, j, instance; - for(i = 0, j = instances.length; i < j; i++) { - instance = instances[i]; - if(instance.$$mdHandle === handle) { - return instance; - } - } - return null; - }, - - /** - * Register an instance. - * @param instance the instance to register - * @param handle the handle to identify the instance under. - */ - register: function(instance, handle) { - if ( !handle ) return angular.noop; - - instance.$$mdHandle = handle; - instances.push(instance); - resolveWhen(); - - return deregister; - - /** - * Remove registration for an instance - */ - function deregister() { - var index = instances.indexOf(instance); - if (index !== -1) { - instances.splice(index, 1); - } - } - - /** - * Resolve any pending promises for this instance - */ - function resolveWhen() { - var dfd = pendings[handle]; - if ( dfd ) { - dfd.resolve( instance ); - delete pendings[handle]; - } - } - }, - - /** - * Async accessor to registered component instance - * If not available then a promise is created to notify - * all listeners when the instance is registered. - */ - when : function(handle) { - if ( isValidID(handle) ) { - var deferred = $q.defer(); - var instance = self.get(handle); - - if ( instance ) { - deferred.resolve( instance ); - } else { - pendings[handle] = deferred; - } - - return deferred.promise; - } - return $q.reject("Invalid `md-component-id` value."); - } - - }; - - function isValidID(handle){ - return handle && (handle !== ""); - } - - } - ComponentRegistry.$inject = ["$log", "$q"]; - -(function() { - 'use strict'; - - /** - * @ngdoc service - * @name $mdButtonInkRipple - * @module material.core - * - * @description - * Provides ripple effects for md-button. See $mdInkRipple service for all possible configuration options. - * - * @param {object=} scope Scope within the current context - * @param {object=} element The element the ripple effect should be applied to - * @param {object=} options (Optional) Configuration options to override the defaultripple configuration - */ - - angular.module('material.core') - .factory('$mdButtonInkRipple', MdButtonInkRipple); - - function MdButtonInkRipple($mdInkRipple) { - return { - attach: attach - }; - - function attach(scope, element, options) { - var elementOptions = optionsForElement(element); - return $mdInkRipple.attach(scope, element, angular.extend(elementOptions, options)); - }; - - function optionsForElement(element) { - if (element.hasClass('md-icon-button')) { - return { - isMenuItem: element.hasClass('md-menu-item'), - fitRipple: true, - center: true - }; - } else { - return { - isMenuItem: element.hasClass('md-menu-item'), - dimBackground: true - } - } - }; - } - MdButtonInkRipple.$inject = ["$mdInkRipple"];; -})(); - -(function() { - 'use strict'; - - /** - * @ngdoc service - * @name $mdCheckboxInkRipple - * @module material.core - * - * @description - * Provides ripple effects for md-checkbox. See $mdInkRipple service for all possible configuration options. - * - * @param {object=} scope Scope within the current context - * @param {object=} element The element the ripple effect should be applied to - * @param {object=} options (Optional) Configuration options to override the defaultripple configuration - */ - - angular.module('material.core') - .factory('$mdCheckboxInkRipple', MdCheckboxInkRipple); - - function MdCheckboxInkRipple($mdInkRipple) { - return { - attach: attach - }; - - function attach(scope, element, options) { - return $mdInkRipple.attach(scope, element, angular.extend({ - center: true, - dimBackground: false, - fitRipple: true - }, options)); - }; - } - MdCheckboxInkRipple.$inject = ["$mdInkRipple"];; -})(); - -(function() { - 'use strict'; - - /** - * @ngdoc service - * @name $mdListInkRipple - * @module material.core - * - * @description - * Provides ripple effects for md-list. See $mdInkRipple service for all possible configuration options. - * - * @param {object=} scope Scope within the current context - * @param {object=} element The element the ripple effect should be applied to - * @param {object=} options (Optional) Configuration options to override the defaultripple configuration - */ - - angular.module('material.core') - .factory('$mdListInkRipple', MdListInkRipple); - - function MdListInkRipple($mdInkRipple) { - return { - attach: attach - }; - - function attach(scope, element, options) { - return $mdInkRipple.attach(scope, element, angular.extend({ - center: false, - dimBackground: true, - outline: false, - rippleSize: 'full' - }, options)); - }; - } - MdListInkRipple.$inject = ["$mdInkRipple"];; -})(); - -angular.module('material.core') - .factory('$mdInkRipple', InkRippleService) - .directive('mdInkRipple', InkRippleDirective) - .directive('mdNoInk', attrNoDirective()) - .directive('mdNoBar', attrNoDirective()) - .directive('mdNoStretch', attrNoDirective()); - -function InkRippleDirective($mdButtonInkRipple, $mdCheckboxInkRipple) { - return { - controller: angular.noop, - link: function (scope, element, attr) { - if (attr.hasOwnProperty('mdInkRippleCheckbox')) { - $mdCheckboxInkRipple.attach(scope, element); - } else { - $mdButtonInkRipple.attach(scope, element); - } - } - }; -} -InkRippleDirective.$inject = ["$mdButtonInkRipple", "$mdCheckboxInkRipple"]; - -function InkRippleService($window, $timeout) { - - return { - attach: attach - }; - - function attach(scope, element, options) { - if (element.controller('mdNoInk')) return angular.noop; - - options = angular.extend({ - colorElement: element, - mousedown: true, - hover: true, - focus: true, - center: false, - mousedownPauseTime: 150, - dimBackground: false, - outline: false, - fullRipple: true, - isMenuItem: false, - fitRipple: false - }, options); - - var rippleSize, - controller = element.controller('mdInkRipple') || {}, - counter = 0, - ripples = [], - states = [], - isActiveExpr = element.attr('md-highlight'), - isActive = false, - isHeld = false, - node = element[0], - rippleSizeSetting = element.attr('md-ripple-size'), - color = parseColor(element.attr('md-ink-ripple')) || parseColor(options.colorElement.length && $window.getComputedStyle(options.colorElement[0]).color || 'rgb(0, 0, 0)'); - - switch (rippleSizeSetting) { - case 'full': - options.fullRipple = true; - break; - case 'partial': - options.fullRipple = false; - break; - } - - // expose onInput for ripple testing - if (options.mousedown) { - element.on('$md.pressdown', onPressDown) - .on('$md.pressup', onPressUp); - } - - controller.createRipple = createRipple; - - if (isActiveExpr) { - scope.$watch(isActiveExpr, function watchActive(newValue) { - isActive = newValue; - if (isActive && !ripples.length) { - $timeout(function () { createRipple(0, 0); }, 0, false); - } - angular.forEach(ripples, updateElement); - }); - } - - // Publish self-detach method if desired... - return function detach() { - element.off('$md.pressdown', onPressDown) - .off('$md.pressup', onPressUp); - getRippleContainer().remove(); - }; - - /** - * Gets the current ripple container - * If there is no ripple container, it creates one and returns it - * - * @returns {angular.element} ripple container element - */ - function getRippleContainer() { - var container = element.data('$mdRippleContainer'); - if (container) return container; - container = angular.element('<div class="md-ripple-container">'); - element.append(container); - element.data('$mdRippleContainer', container); - return container; - } - - function parseColor(color) { - if (!color) return; - if (color.indexOf('rgba') === 0) return color.replace(/\d?\.?\d*\s*\)\s*$/, '0.1)'); - if (color.indexOf('rgb') === 0) return rgbToRGBA(color); - if (color.indexOf('#') === 0) return hexToRGBA(color); - - /** - * Converts a hex value to an rgba string - * - * @param {string} hex value (3 or 6 digits) to be converted - * - * @returns {string} rgba color with 0.1 alpha - */ - function hexToRGBA(color) { - var hex = color.charAt(0) === '#' ? color.substr(1) : color, - dig = hex.length / 3, - red = hex.substr(0, dig), - grn = hex.substr(dig, dig), - blu = hex.substr(dig * 2); - if (dig === 1) { - red += red; - grn += grn; - blu += blu; - } - return 'rgba(' + parseInt(red, 16) + ',' + parseInt(grn, 16) + ',' + parseInt(blu, 16) + ',0.1)'; - } - - /** - * Converts rgb value to rgba string - * - * @param {string} rgb color string - * - * @returns {string} rgba color with 0.1 alpha - */ - function rgbToRGBA(color) { - return color.replace(')', ', 0.1)').replace('(', 'a('); - } - - } - - function removeElement(elem, wait) { - ripples.splice(ripples.indexOf(elem), 1); - if (ripples.length === 0) { - getRippleContainer().css({ backgroundColor: '' }); - } - $timeout(function () { elem.remove(); }, wait, false); - } - - function updateElement(elem) { - var index = ripples.indexOf(elem), - state = states[index] || {}, - elemIsActive = ripples.length > 1 ? false : isActive, - elemIsHeld = ripples.length > 1 ? false : isHeld; - if (elemIsActive || state.animating || elemIsHeld) { - elem.addClass('md-ripple-visible'); - } else if (elem) { - elem.removeClass('md-ripple-visible'); - if (options.outline) { - elem.css({ - width: rippleSize + 'px', - height: rippleSize + 'px', - marginLeft: (rippleSize * -1) + 'px', - marginTop: (rippleSize * -1) + 'px' - }); - } - removeElement(elem, options.outline ? 450 : 650); - } - } - - /** - * Creates a ripple at the provided coordinates - * - * @param {number} left cursor position - * @param {number} top cursor position - * - * @returns {angular.element} the generated ripple element - */ - function createRipple(left, top) { - - color = parseColor(element.attr('md-ink-ripple')) || parseColor($window.getComputedStyle(options.colorElement[0]).color || 'rgb(0, 0, 0)'); - - var container = getRippleContainer(), - size = getRippleSize(left, top), - css = getRippleCss(size, left, top), - elem = getRippleElement(css), - index = ripples.indexOf(elem), - state = states[index] || {}; - - rippleSize = size; - - state.animating = true; - - $timeout(function () { - if (options.dimBackground) { - container.css({ backgroundColor: color }); - } - elem.addClass('md-ripple-placed md-ripple-scaled'); - if (options.outline) { - elem.css({ - borderWidth: (size * 0.5) + 'px', - marginLeft: (size * -0.5) + 'px', - marginTop: (size * -0.5) + 'px' - }); - } else { - elem.css({ left: '50%', top: '50%' }); - } - updateElement(elem); - $timeout(function () { - state.animating = false; - updateElement(elem); - }, (options.outline ? 450 : 225), false); - }, 0, false); - - return elem; - - /** - * Creates the ripple element with the provided css - * - * @param {object} css properties to be applied - * - * @returns {angular.element} the generated ripple element - */ - function getRippleElement(css) { - var elem = angular.element('<div class="md-ripple" data-counter="' + counter++ + '">'); - ripples.unshift(elem); - states.unshift({ animating: true }); - container.append(elem); - css && elem.css(css); - return elem; - } - - /** - * Calculate the ripple size - * - * @returns {number} calculated ripple diameter - */ - function getRippleSize(left, top) { - var width = container.prop('offsetWidth'), - height = container.prop('offsetHeight'), - multiplier, size, rect; - if (options.isMenuItem) { - size = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); - } else if (options.outline) { - rect = node.getBoundingClientRect(); - left -= rect.left; - top -= rect.top; - width = Math.max(left, width - left); - height = Math.max(top, height - top); - size = 2 * Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); - } else { - multiplier = options.fullRipple ? 1.1 : 0.8; - size = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) * multiplier; - if (options.fitRipple) { - size = Math.min(height, width, size); - } - } - return size; - } - - /** - * Generates the ripple css - * - * @param {number} the diameter of the ripple - * @param {number} the left cursor offset - * @param {number} the top cursor offset - * - * @returns {{backgroundColor: string, borderColor: string, width: string, height: string}} - */ - function getRippleCss(size, left, top) { - var rect = node.getBoundingClientRect(), - css = { - backgroundColor: rgbaToRGB(color), - borderColor: rgbaToRGB(color), - width: size + 'px', - height: size + 'px' - }; - - if (options.outline) { - css.width = 0; - css.height = 0; - } else { - css.marginLeft = css.marginTop = (size * -0.5) + 'px'; - } - - if (options.center) { - css.left = css.top = '50%'; - } else { - css.left = Math.round((left - rect.left) / container.prop('offsetWidth') * 100) + '%'; - css.top = Math.round((top - rect.top) / container.prop('offsetHeight') * 100) + '%'; - } - - return css; - - /** - * Converts rgba string to rgb, removing the alpha value - * - * @param {string} rgba color - * - * @returns {string} rgb color - */ - function rgbaToRGB(color) { - return color.replace('rgba', 'rgb').replace(/,[^\),]+\)/, ')'); - } - } - } - - /** - * Handles user input start and stop events - * - */ - function onPressDown(ev) { - if (!isRippleAllowed()) return; - - createRipple(ev.pointer.x, ev.pointer.y); - isHeld = true; - } - function onPressUp() { - isHeld = false; - var ripple = ripples[ ripples.length - 1 ]; - $timeout(function () { updateElement(ripple); }, 0, false); - } - - /** - * Determines if the ripple is allowed - * - * @returns {boolean} true if the ripple is allowed, false if not - */ - function isRippleAllowed() { - var parent = node.parentNode; - var grandparent = parent && parent.parentNode; - var ancestor = grandparent && grandparent.parentNode; - return !isDisabled(node) && !isDisabled(parent) && !isDisabled(grandparent) && !isDisabled(ancestor); - function isDisabled (elem) { - return elem && elem.hasAttribute && elem.hasAttribute('disabled'); - } - } - - } -} -InkRippleService.$inject = ["$window", "$timeout"]; - -/** - * noink/nobar/nostretch directive: make any element that has one of - * these attributes be given a controller, so that other directives can - * `require:` these and see if there is a `no<xxx>` parent attribute. - * - * @usage - * <hljs lang="html"> - * <parent md-no-ink> - * <child detect-no> - * </child> - * </parent> - * </hljs> - * - * <hljs lang="js"> - * myApp.directive('detectNo', function() { - * return { - * require: ['^?mdNoInk', ^?mdNoBar'], - * link: function(scope, element, attr, ctrls) { - * var noinkCtrl = ctrls[0]; - * var nobarCtrl = ctrls[1]; - * if (noInkCtrl) { - * alert("the md-no-ink flag has been specified on an ancestor!"); - * } - * if (nobarCtrl) { - * alert("the md-no-bar flag has been specified on an ancestor!"); - * } - * } - * }; - * }); - * </hljs> - */ -function attrNoDirective() { - return function() { - return { - controller: angular.noop - }; - }; -} - -(function() { - 'use strict'; - - /** - * @ngdoc service - * @name $mdTabInkRipple - * @module material.core - * - * @description - * Provides ripple effects for md-tabs. See $mdInkRipple service for all possible configuration options. - * - * @param {object=} scope Scope within the current context - * @param {object=} element The element the ripple effect should be applied to - * @param {object=} options (Optional) Configuration options to override the defaultripple configuration - */ - - angular.module('material.core') - .factory('$mdTabInkRipple', MdTabInkRipple); - - function MdTabInkRipple($mdInkRipple) { - return { - attach: attach - }; - - function attach(scope, element, options) { - return $mdInkRipple.attach(scope, element, angular.extend({ - center: false, - dimBackground: true, - outline: false, - rippleSize: 'full' - }, options)); - }; - } - MdTabInkRipple.$inject = ["$mdInkRipple"];; -})(); - -angular.module('material.core.theming.palette', []) -.constant('$mdColorPalette', { - 'red': { - '50': '#ffebee', - '100': '#ffcdd2', - '200': '#ef9a9a', - '300': '#e57373', - '400': '#ef5350', - '500': '#f44336', - '600': '#e53935', - '700': '#d32f2f', - '800': '#c62828', - '900': '#b71c1c', - 'A100': '#ff8a80', - 'A200': '#ff5252', - 'A400': '#ff1744', - 'A700': '#d50000', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 300 400 A100', - 'contrastStrongLightColors': '500 600 700 A200 A400 A700' - }, - 'pink': { - '50': '#fce4ec', - '100': '#f8bbd0', - '200': '#f48fb1', - '300': '#f06292', - '400': '#ec407a', - '500': '#e91e63', - '600': '#d81b60', - '700': '#c2185b', - '800': '#ad1457', - '900': '#880e4f', - 'A100': '#ff80ab', - 'A200': '#ff4081', - 'A400': '#f50057', - 'A700': '#c51162', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 300 400 A100', - 'contrastStrongLightColors': '500 600 A200 A400 A700' - }, - 'purple': { - '50': '#f3e5f5', - '100': '#e1bee7', - '200': '#ce93d8', - '300': '#ba68c8', - '400': '#ab47bc', - '500': '#9c27b0', - '600': '#8e24aa', - '700': '#7b1fa2', - '800': '#6a1b9a', - '900': '#4a148c', - 'A100': '#ea80fc', - 'A200': '#e040fb', - 'A400': '#d500f9', - 'A700': '#aa00ff', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 A100', - 'contrastStrongLightColors': '300 400 A200 A400 A700' - }, - 'deep-purple': { - '50': '#ede7f6', - '100': '#d1c4e9', - '200': '#b39ddb', - '300': '#9575cd', - '400': '#7e57c2', - '500': '#673ab7', - '600': '#5e35b1', - '700': '#512da8', - '800': '#4527a0', - '900': '#311b92', - 'A100': '#b388ff', - 'A200': '#7c4dff', - 'A400': '#651fff', - 'A700': '#6200ea', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 A100', - 'contrastStrongLightColors': '300 400 A200' - }, - 'indigo': { - '50': '#e8eaf6', - '100': '#c5cae9', - '200': '#9fa8da', - '300': '#7986cb', - '400': '#5c6bc0', - '500': '#3f51b5', - '600': '#3949ab', - '700': '#303f9f', - '800': '#283593', - '900': '#1a237e', - 'A100': '#8c9eff', - 'A200': '#536dfe', - 'A400': '#3d5afe', - 'A700': '#304ffe', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 A100', - 'contrastStrongLightColors': '300 400 A200 A400' - }, - 'blue': { - '50': '#e3f2fd', - '100': '#bbdefb', - '200': '#90caf9', - '300': '#64b5f6', - '400': '#42a5f5', - '500': '#2196f3', - '600': '#1e88e5', - '700': '#1976d2', - '800': '#1565c0', - '900': '#0d47a1', - 'A100': '#82b1ff', - 'A200': '#448aff', - 'A400': '#2979ff', - 'A700': '#2962ff', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '100 200 300 400 A100', - 'contrastStrongLightColors': '500 600 700 A200 A400 A700' - }, - 'light-blue': { - '50': '#e1f5fe', - '100': '#b3e5fc', - '200': '#81d4fa', - '300': '#4fc3f7', - '400': '#29b6f6', - '500': '#03a9f4', - '600': '#039be5', - '700': '#0288d1', - '800': '#0277bd', - '900': '#01579b', - 'A100': '#80d8ff', - 'A200': '#40c4ff', - 'A400': '#00b0ff', - 'A700': '#0091ea', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '500 600 700 800 900 A700', - 'contrastStrongLightColors': '500 600 700 800 A700' - }, - 'cyan': { - '50': '#e0f7fa', - '100': '#b2ebf2', - '200': '#80deea', - '300': '#4dd0e1', - '400': '#26c6da', - '500': '#00bcd4', - '600': '#00acc1', - '700': '#0097a7', - '800': '#00838f', - '900': '#006064', - 'A100': '#84ffff', - 'A200': '#18ffff', - 'A400': '#00e5ff', - 'A700': '#00b8d4', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '500 600 700 800 900', - 'contrastStrongLightColors': '500 600 700 800' - }, - 'teal': { - '50': '#e0f2f1', - '100': '#b2dfdb', - '200': '#80cbc4', - '300': '#4db6ac', - '400': '#26a69a', - '500': '#009688', - '600': '#00897b', - '700': '#00796b', - '800': '#00695c', - '900': '#004d40', - 'A100': '#a7ffeb', - 'A200': '#64ffda', - 'A400': '#1de9b6', - 'A700': '#00bfa5', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '500 600 700 800 900', - 'contrastStrongLightColors': '500 600 700' - }, - 'green': { - '50': '#e8f5e9', - '100': '#c8e6c9', - '200': '#a5d6a7', - '300': '#81c784', - '400': '#66bb6a', - '500': '#4caf50', - '600': '#43a047', - '700': '#388e3c', - '800': '#2e7d32', - '900': '#1b5e20', - 'A100': '#b9f6ca', - 'A200': '#69f0ae', - 'A400': '#00e676', - 'A700': '#00c853', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '500 600 700 800 900', - 'contrastStrongLightColors': '500 600 700' - }, - 'light-green': { - '50': '#f1f8e9', - '100': '#dcedc8', - '200': '#c5e1a5', - '300': '#aed581', - '400': '#9ccc65', - '500': '#8bc34a', - '600': '#7cb342', - '700': '#689f38', - '800': '#558b2f', - '900': '#33691e', - 'A100': '#ccff90', - 'A200': '#b2ff59', - 'A400': '#76ff03', - 'A700': '#64dd17', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '800 900', - 'contrastStrongLightColors': '800 900' - }, - 'lime': { - '50': '#f9fbe7', - '100': '#f0f4c3', - '200': '#e6ee9c', - '300': '#dce775', - '400': '#d4e157', - '500': '#cddc39', - '600': '#c0ca33', - '700': '#afb42b', - '800': '#9e9d24', - '900': '#827717', - 'A100': '#f4ff81', - 'A200': '#eeff41', - 'A400': '#c6ff00', - 'A700': '#aeea00', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '900', - 'contrastStrongLightColors': '900' - }, - 'yellow': { - '50': '#fffde7', - '100': '#fff9c4', - '200': '#fff59d', - '300': '#fff176', - '400': '#ffee58', - '500': '#ffeb3b', - '600': '#fdd835', - '700': '#fbc02d', - '800': '#f9a825', - '900': '#f57f17', - 'A100': '#ffff8d', - 'A200': '#ffff00', - 'A400': '#ffea00', - 'A700': '#ffd600', - 'contrastDefaultColor': 'dark' - }, - 'amber': { - '50': '#fff8e1', - '100': '#ffecb3', - '200': '#ffe082', - '300': '#ffd54f', - '400': '#ffca28', - '500': '#ffc107', - '600': '#ffb300', - '700': '#ffa000', - '800': '#ff8f00', - '900': '#ff6f00', - 'A100': '#ffe57f', - 'A200': '#ffd740', - 'A400': '#ffc400', - 'A700': '#ffab00', - 'contrastDefaultColor': 'dark' - }, - 'orange': { - '50': '#fff3e0', - '100': '#ffe0b2', - '200': '#ffcc80', - '300': '#ffb74d', - '400': '#ffa726', - '500': '#ff9800', - '600': '#fb8c00', - '700': '#f57c00', - '800': '#ef6c00', - '900': '#e65100', - 'A100': '#ffd180', - 'A200': '#ffab40', - 'A400': '#ff9100', - 'A700': '#ff6d00', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '800 900', - 'contrastStrongLightColors': '800 900' - }, - 'deep-orange': { - '50': '#fbe9e7', - '100': '#ffccbc', - '200': '#ffab91', - '300': '#ff8a65', - '400': '#ff7043', - '500': '#ff5722', - '600': '#f4511e', - '700': '#e64a19', - '800': '#d84315', - '900': '#bf360c', - 'A100': '#ff9e80', - 'A200': '#ff6e40', - 'A400': '#ff3d00', - 'A700': '#dd2c00', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 300 400 A100 A200', - 'contrastStrongLightColors': '500 600 700 800 900 A400 A700' - }, - 'brown': { - '50': '#efebe9', - '100': '#d7ccc8', - '200': '#bcaaa4', - '300': '#a1887f', - '400': '#8d6e63', - '500': '#795548', - '600': '#6d4c41', - '700': '#5d4037', - '800': '#4e342e', - '900': '#3e2723', - 'A100': '#d7ccc8', - 'A200': '#bcaaa4', - 'A400': '#8d6e63', - 'A700': '#5d4037', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200', - 'contrastStrongLightColors': '300 400' - }, - 'grey': { - '50': '#fafafa', - '100': '#f5f5f5', - '200': '#eeeeee', - '300': '#e0e0e0', - '400': '#bdbdbd', - '500': '#9e9e9e', - '600': '#757575', - '700': '#616161', - '800': '#424242', - '900': '#212121', - '1000': '#000000', - 'A100': '#ffffff', - 'A200': '#eeeeee', - 'A400': '#bdbdbd', - 'A700': '#616161', - 'contrastDefaultColor': 'dark', - 'contrastLightColors': '600 700 800 900' - }, - 'blue-grey': { - '50': '#eceff1', - '100': '#cfd8dc', - '200': '#b0bec5', - '300': '#90a4ae', - '400': '#78909c', - '500': '#607d8b', - '600': '#546e7a', - '700': '#455a64', - '800': '#37474f', - '900': '#263238', - 'A100': '#cfd8dc', - 'A200': '#b0bec5', - 'A400': '#78909c', - 'A700': '#455a64', - 'contrastDefaultColor': 'light', - 'contrastDarkColors': '50 100 200 300', - 'contrastStrongLightColors': '400 500' - } -}); - -angular.module('material.core.theming', ['material.core.theming.palette']) - .directive('mdTheme', ThemingDirective) - .directive('mdThemable', ThemableDirective) - .provider('$mdTheming', ThemingProvider) - .run(generateThemes); - -/** - * @ngdoc provider - * @name $mdThemingProvider - * @module material.core - * - * @description Provider to configure the `$mdTheming` service. - */ - -/** - * @ngdoc method - * @name $mdThemingProvider#setDefaultTheme - * @param {string} themeName Default theme name to be applied to elements. Default value is `default`. - */ - -/** - * @ngdoc method - * @name $mdThemingProvider#alwaysWatchTheme - * @param {boolean} watch Whether or not to always watch themes for changes and re-apply - * classes when they change. Default is `false`. Enabling can reduce performance. - */ - -/* Some Example Valid Theming Expressions - * ======================================= - * - * Intention group expansion: (valid for primary, accent, warn, background) - * - * {{primary-100}} - grab shade 100 from the primary palette - * {{primary-100-0.7}} - grab shade 100, apply opacity of 0.7 - * {{primary-hue-1}} - grab the shade assigned to hue-1 from the primary palette - * {{primary-hue-1-0.7}} - apply 0.7 opacity to primary-hue-1 - * {{primary-color}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured shades set for each hue - * {{primary-color-0.7}} - Apply 0.7 opacity to each of the above rules - * {{primary-contrast}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured contrast (ie. text) color shades set for each hue - * {{primary-contrast-0.7}} - Apply 0.7 opacity to each of the above rules - * - * Foreground expansion: Applies rgba to black/white foreground text - * - * {{foreground-1}} - used for primary text - * {{foreground-2}} - used for secondary text/divider - * {{foreground-3}} - used for disabled text - * {{foreground-4}} - used for dividers - * - */ - -// In memory generated CSS rules; registered by theme.name -var GENERATED = { }; - -// In memory storage of defined themes and color palettes (both loaded by CSS, and user specified) -var PALETTES; -var THEMES; - -var DARK_FOREGROUND = { - name: 'dark', - '1': 'rgba(0,0,0,0.87)', - '2': 'rgba(0,0,0,0.54)', - '3': 'rgba(0,0,0,0.26)', - '4': 'rgba(0,0,0,0.12)' -}; -var LIGHT_FOREGROUND = { - name: 'light', - '1': 'rgba(255,255,255,1.0)', - '2': 'rgba(255,255,255,0.7)', - '3': 'rgba(255,255,255,0.3)', - '4': 'rgba(255,255,255,0.12)' -}; - -var DARK_SHADOW = '1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)'; -var LIGHT_SHADOW = ''; - -var DARK_CONTRAST_COLOR = colorToRgbaArray('rgba(0,0,0,0.87)'); -var LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgba(255,255,255,0.87'); -var STRONG_LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgb(255,255,255)'); - -var THEME_COLOR_TYPES = ['primary', 'accent', 'warn', 'background']; -var DEFAULT_COLOR_TYPE = 'primary'; - -// A color in a theme will use these hues by default, if not specified by user. -var LIGHT_DEFAULT_HUES = { - 'accent': { - 'default': 'A200', - 'hue-1': 'A100', - 'hue-2': 'A400', - 'hue-3': 'A700' - }, - 'background': { - 'default': 'A100', - 'hue-1': '300', - 'hue-2': '800', - 'hue-3': '900' - } -}; - -var DARK_DEFAULT_HUES = { - 'background': { - 'default': '800', - 'hue-1': '300', - 'hue-2': '600', - 'hue-3': '900' - } -}; -THEME_COLOR_TYPES.forEach(function(colorType) { - // Color types with unspecified default hues will use these default hue values - var defaultDefaultHues = { - 'default': '500', - 'hue-1': '300', - 'hue-2': '800', - 'hue-3': 'A100' - }; - if (!LIGHT_DEFAULT_HUES[colorType]) LIGHT_DEFAULT_HUES[colorType] = defaultDefaultHues; - if (!DARK_DEFAULT_HUES[colorType]) DARK_DEFAULT_HUES[colorType] = defaultDefaultHues; -}); - -var VALID_HUE_VALUES = [ - '50', '100', '200', '300', '400', '500', '600', - '700', '800', '900', 'A100', 'A200', 'A400', 'A700' -]; - -function ThemingProvider($mdColorPalette) { - PALETTES = { }; - THEMES = { }; - - var themingProvider; - var defaultTheme = 'default'; - var alwaysWatchTheme = false; - - // Load JS Defined Palettes - angular.extend(PALETTES, $mdColorPalette); - - // Default theme defined in core.js - - ThemingService.$inject = ["$rootScope", "$log"]; - return themingProvider = { - definePalette: definePalette, - extendPalette: extendPalette, - theme: registerTheme, - - setDefaultTheme: function(theme) { - defaultTheme = theme; - }, - alwaysWatchTheme: function(alwaysWatch) { - alwaysWatchTheme = alwaysWatch; - }, - $get: ThemingService, - _LIGHT_DEFAULT_HUES: LIGHT_DEFAULT_HUES, - _DARK_DEFAULT_HUES: DARK_DEFAULT_HUES, - _PALETTES: PALETTES, - _THEMES: THEMES, - _parseRules: parseRules, - _rgba: rgba - }; - - // Example: $mdThemingProvider.definePalette('neonRed', { 50: '#f5fafa', ... }); - function definePalette(name, map) { - map = map || {}; - PALETTES[name] = checkPaletteValid(name, map); - return themingProvider; - } - - // Returns an new object which is a copy of a given palette `name` with variables from - // `map` overwritten - // Example: var neonRedMap = $mdThemingProvider.extendPalette('red', { 50: '#f5fafafa' }); - function extendPalette(name, map) { - return checkPaletteValid(name, angular.extend({}, PALETTES[name] || {}, map) ); - } - - // Make sure that palette has all required hues - function checkPaletteValid(name, map) { - var missingColors = VALID_HUE_VALUES.filter(function(field) { - return !map[field]; - }); - if (missingColors.length) { - throw new Error("Missing colors %1 in palette %2!" - .replace('%1', missingColors.join(', ')) - .replace('%2', name)); - } - - return map; - } - - // Register a theme (which is a collection of color palettes to use with various states - // ie. warn, accent, primary ) - // Optionally inherit from an existing theme - // $mdThemingProvider.theme('custom-theme').primaryPalette('red'); - function registerTheme(name, inheritFrom) { - if (THEMES[name]) return THEMES[name]; - - inheritFrom = inheritFrom || 'default'; - - var parentTheme = typeof inheritFrom === 'string' ? THEMES[inheritFrom] : inheritFrom; - var theme = new Theme(name); - - if (parentTheme) { - angular.forEach(parentTheme.colors, function(color, colorType) { - theme.colors[colorType] = { - name: color.name, - // Make sure a COPY of the hues is given to the child color, - // not the same reference. - hues: angular.extend({}, color.hues) - }; - }); - } - THEMES[name] = theme; - - return theme; - } - - function Theme(name) { - var self = this; - self.name = name; - self.colors = {}; - - self.dark = setDark; - setDark(false); - - function setDark(isDark) { - isDark = arguments.length === 0 ? true : !!isDark; - - // If no change, abort - if (isDark === self.isDark) return; - - self.isDark = isDark; - - self.foregroundPalette = self.isDark ? LIGHT_FOREGROUND : DARK_FOREGROUND; - self.foregroundShadow = self.isDark ? DARK_SHADOW : LIGHT_SHADOW; - - // Light and dark themes have different default hues. - // Go through each existing color type for this theme, and for every - // hue value that is still the default hue value from the previous light/dark setting, - // set it to the default hue value from the new light/dark setting. - var newDefaultHues = self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES; - var oldDefaultHues = self.isDark ? LIGHT_DEFAULT_HUES : DARK_DEFAULT_HUES; - angular.forEach(newDefaultHues, function(newDefaults, colorType) { - var color = self.colors[colorType]; - var oldDefaults = oldDefaultHues[colorType]; - if (color) { - for (var hueName in color.hues) { - if (color.hues[hueName] === oldDefaults[hueName]) { - color.hues[hueName] = newDefaults[hueName]; - } - } - } - }); - - return self; - } - - THEME_COLOR_TYPES.forEach(function(colorType) { - var defaultHues = (self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES)[colorType]; - self[colorType + 'Palette'] = function setPaletteType(paletteName, hues) { - var color = self.colors[colorType] = { - name: paletteName, - hues: angular.extend({}, defaultHues, hues) - }; - - Object.keys(color.hues).forEach(function(name) { - if (!defaultHues[name]) { - throw new Error("Invalid hue name '%1' in theme %2's %3 color %4. Available hue names: %4" - .replace('%1', name) - .replace('%2', self.name) - .replace('%3', paletteName) - .replace('%4', Object.keys(defaultHues).join(', ')) - ); - } - }); - Object.keys(color.hues).map(function(key) { - return color.hues[key]; - }).forEach(function(hueValue) { - if (VALID_HUE_VALUES.indexOf(hueValue) == -1) { - throw new Error("Invalid hue value '%1' in theme %2's %3 color %4. Available hue values: %5" - .replace('%1', hueValue) - .replace('%2', self.name) - .replace('%3', colorType) - .replace('%4', paletteName) - .replace('%5', VALID_HUE_VALUES.join(', ')) - ); - } - }); - return self; - }; - - self[colorType + 'Color'] = function() { - var args = Array.prototype.slice.call(arguments); - console.warn('$mdThemingProviderTheme.' + colorType + 'Color() has been deprecated. ' + - 'Use $mdThemingProviderTheme.' + colorType + 'Palette() instead.'); - return self[colorType + 'Palette'].apply(self, args); - }; - }); - } - - /** - * @ngdoc service - * @name $mdTheming - * - * @description - * - * Service that makes an element apply theming related classes to itself. - * - * ```js - * app.directive('myFancyDirective', function($mdTheming) { - * return { - * restrict: 'e', - * link: function(scope, el, attrs) { - * $mdTheming(el); - * } - * }; - * }); - * ``` - * @param {el=} element to apply theming to - */ - /* ngInject */ - function ThemingService($rootScope, $log) { - - applyTheme.inherit = function(el, parent) { - var ctrl = parent.controller('mdTheme'); - - var attrThemeValue = el.attr('md-theme-watch'); - if ( (alwaysWatchTheme || angular.isDefined(attrThemeValue)) && attrThemeValue != 'false') { - var deregisterWatch = $rootScope.$watch(function() { - return ctrl && ctrl.$mdTheme || defaultTheme; - }, changeTheme); - el.on('$destroy', deregisterWatch); - } else { - var theme = ctrl && ctrl.$mdTheme || defaultTheme; - changeTheme(theme); - } - - function changeTheme(theme) { - if (!registered(theme)) { - $log.warn('Attempted to use unregistered theme \'' + theme + '\'. ' + - 'Register it with $mdThemingProvider.theme().'); - } - var oldTheme = el.data('$mdThemeName'); - if (oldTheme) el.removeClass('md-' + oldTheme +'-theme'); - el.addClass('md-' + theme + '-theme'); - el.data('$mdThemeName', theme); - } - }; - - applyTheme.THEMES = angular.extend({}, THEMES); - applyTheme.defaultTheme = function() { return defaultTheme; }; - applyTheme.registered = registered; - - return applyTheme; - - function registered(themeName) { - if (themeName === undefined || themeName === '') return true; - return applyTheme.THEMES[themeName] !== undefined; - } - - function applyTheme(scope, el) { - // Allow us to be invoked via a linking function signature. - if (el === undefined) { - el = scope; - scope = undefined; - } - if (scope === undefined) { - scope = $rootScope; - } - applyTheme.inherit(el, el); - } - } -} -ThemingProvider.$inject = ["$mdColorPalette"]; - -function ThemingDirective($mdTheming, $interpolate, $log) { - return { - priority: 100, - link: { - pre: function(scope, el, attrs) { - var ctrl = { - $setTheme: function(theme) { - if (!$mdTheming.registered(theme)) { - $log.warn('attempted to use unregistered theme \'' + theme + '\''); - } - ctrl.$mdTheme = theme; - } - }; - el.data('$mdThemeController', ctrl); - ctrl.$setTheme($interpolate(attrs.mdTheme)(scope)); - attrs.$observe('mdTheme', ctrl.$setTheme); - } - } - }; -} -ThemingDirective.$inject = ["$mdTheming", "$interpolate", "$log"]; - -function ThemableDirective($mdTheming) { - return $mdTheming; -} -ThemableDirective.$inject = ["$mdTheming"]; - -function parseRules(theme, colorType, rules) { - checkValidPalette(theme, colorType); - - rules = rules.replace(/THEME_NAME/g, theme.name); - var generatedRules = []; - var color = theme.colors[colorType]; - - var themeNameRegex = new RegExp('.md-' + theme.name + '-theme', 'g'); - // Matches '{{ primary-color }}', etc - var hueRegex = new RegExp('(\'|")?{{\\s*(' + colorType + ')-(color|contrast)-?(\\d\\.?\\d*)?\\s*}}(\"|\')?','g'); - var simpleVariableRegex = /'?"?\{\{\s*([a-zA-Z]+)-(A?\d+|hue\-[0-3]|shadow)-?(\d\.?\d*)?\s*\}\}'?"?/g; - var palette = PALETTES[color.name]; - - // find and replace simple variables where we use a specific hue, not an entire palette - // eg. "{{primary-100}}" - //\(' + THEME_COLOR_TYPES.join('\|') + '\)' - rules = rules.replace(simpleVariableRegex, function(match, colorType, hue, opacity) { - if (colorType === 'foreground') { - if (hue == 'shadow') { - return theme.foregroundShadow; - } else { - return theme.foregroundPalette[hue] || theme.foregroundPalette['1']; - } - } - if (hue.indexOf('hue') === 0) { - hue = theme.colors[colorType].hues[hue]; - } - return rgba( (PALETTES[ theme.colors[colorType].name ][hue] || '').value, opacity ); - }); - - // For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3) - angular.forEach(color.hues, function(hueValue, hueName) { - var newRule = rules - .replace(hueRegex, function(match, _, colorType, hueType, opacity) { - return rgba(palette[hueValue][hueType === 'color' ? 'value' : 'contrast'], opacity); - }); - if (hueName !== 'default') { - newRule = newRule.replace(themeNameRegex, '.md-' + theme.name + '-theme.md-' + hueName); - } - - // Don't apply a selector rule to the default theme, making it easier to override - // styles of the base-component - if (theme.name == 'default') { - newRule = newRule.replace(/\.md-default-theme/g, ''); - } - generatedRules.push(newRule); - }); - - return generatedRules; -} - -// Generate our themes at run time given the state of THEMES and PALETTES -function generateThemes($injector) { - - var head = document.getElementsByTagName('head')[0]; - var firstChild = head ? head.firstElementChild : null; - var themeCss = $injector.has('$MD_THEME_CSS') ? $injector.get('$MD_THEME_CSS') : ''; - - if ( !firstChild ) return; - if (themeCss.length === 0) return; // no rules, so no point in running this expensive task - - // Expose contrast colors for palettes to ensure that text is always readable - angular.forEach(PALETTES, sanitizePalette); - - // MD_THEME_CSS is a string generated by the build process that includes all the themable - // components as templates - - // Break the CSS into individual rules - var rulesByType = {}; - var rules = themeCss - .split(/\}(?!(\}|'|"|;))/) - .filter(function(rule) { return rule && rule.length; }) - .map(function(rule) { return rule.trim() + '}'; }); - - - var ruleMatchRegex = new RegExp('md-(' + THEME_COLOR_TYPES.join('|') + ')', 'g'); - - THEME_COLOR_TYPES.forEach(function(type) { - rulesByType[type] = ''; - }); - - - // Sort the rules based on type, allowing us to do color substitution on a per-type basis - rules.forEach(function(rule) { - var match = rule.match(ruleMatchRegex); - // First: test that if the rule has '.md-accent', it goes into the accent set of rules - for (var i = 0, type; type = THEME_COLOR_TYPES[i]; i++) { - if (rule.indexOf('.md-' + type) > -1) { - return rulesByType[type] += rule; - } - } - - // If no eg 'md-accent' class is found, try to just find 'accent' in the rule and guess from - // there - for (i = 0; type = THEME_COLOR_TYPES[i]; i++) { - if (rule.indexOf(type) > -1) { - return rulesByType[type] += rule; - } - } - - // Default to the primary array - return rulesByType[DEFAULT_COLOR_TYPE] += rule; - }); - - // For each theme, use the color palettes specified for - // `primary`, `warn` and `accent` to generate CSS rules. - - angular.forEach(THEMES, function(theme) { - if ( !GENERATED[theme.name] ) { - - - THEME_COLOR_TYPES.forEach(function(colorType) { - var styleStrings = parseRules(theme, colorType, rulesByType[colorType]); - while (styleStrings.length) { - var style = document.createElement('style'); - style.setAttribute('type', 'text/css'); - style.appendChild(document.createTextNode(styleStrings.shift())); - head.insertBefore(style, firstChild); - } - }); - - - if (theme.colors.primary.name == theme.colors.accent.name) { - console.warn("$mdThemingProvider: Using the same palette for primary and" + - " accent. This violates the material design spec."); - } - - GENERATED[theme.name] = true; - } - }); - - - // ************************* - // Internal functions - // ************************* - - // The user specifies a 'default' contrast color as either light or dark, - // then explicitly lists which hues are the opposite contrast (eg. A100 has dark, A200 has light) - function sanitizePalette(palette) { - var defaultContrast = palette.contrastDefaultColor; - var lightColors = palette.contrastLightColors || []; - var strongLightColors = palette.contrastStrongLightColors || []; - var darkColors = palette.contrastDarkColors || []; - - // These colors are provided as space-separated lists - if (typeof lightColors === 'string') lightColors = lightColors.split(' '); - if (typeof strongLightColors === 'string') strongLightColors = strongLightColors.split(' '); - if (typeof darkColors === 'string') darkColors = darkColors.split(' '); - - // Cleanup after ourselves - delete palette.contrastDefaultColor; - delete palette.contrastLightColors; - delete palette.contrastStrongLightColors; - delete palette.contrastDarkColors; - - // Change { 'A100': '#fffeee' } to { 'A100': { value: '#fffeee', contrast:DARK_CONTRAST_COLOR } - angular.forEach(palette, function(hueValue, hueName) { - if (angular.isObject(hueValue)) return; // Already converted - // Map everything to rgb colors - var rgbValue = colorToRgbaArray(hueValue); - if (!rgbValue) { - throw new Error("Color %1, in palette %2's hue %3, is invalid. Hex or rgb(a) color expected." - .replace('%1', hueValue) - .replace('%2', palette.name) - .replace('%3', hueName)); - } - - palette[hueName] = { - value: rgbValue, - contrast: getContrastColor() - }; - function getContrastColor() { - if (defaultContrast === 'light') { - if (darkColors.indexOf(hueName) > -1) { - return DARK_CONTRAST_COLOR; - } else { - return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR - : LIGHT_CONTRAST_COLOR; - } - } else { - if (lightColors.indexOf(hueName) > -1) { - return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR - : LIGHT_CONTRAST_COLOR; - } else { - return DARK_CONTRAST_COLOR; - } - } - } - }); - } - - -} -generateThemes.$inject = ["$injector"]; - -function checkValidPalette(theme, colorType) { - // If theme attempts to use a palette that doesnt exist, throw error - if (!PALETTES[ (theme.colors[colorType] || {}).name ]) { - throw new Error( - "You supplied an invalid color palette for theme %1's %2 palette. Available palettes: %3" - .replace('%1', theme.name) - .replace('%2', colorType) - .replace('%3', Object.keys(PALETTES).join(', ')) - ); - } -} - -function colorToRgbaArray(clr) { - if (angular.isArray(clr) && clr.length == 3) return clr; - if (/^rgb/.test(clr)) { - return clr.replace(/(^\s*rgba?\(|\)\s*$)/g, '').split(',').map(function(value, i) { - return i == 3 ? parseFloat(value, 10) : parseInt(value, 10); - }); - } - if (clr.charAt(0) == '#') clr = clr.substring(1); - if (!/^([a-fA-F0-9]{3}){1,2}$/g.test(clr)) return; - - var dig = clr.length / 3; - var red = clr.substr(0, dig); - var grn = clr.substr(dig, dig); - var blu = clr.substr(dig * 2); - if (dig === 1) { - red += red; - grn += grn; - blu += blu; - } - return [parseInt(red, 16), parseInt(grn, 16), parseInt(blu, 16)]; -} - -function rgba(rgbArray, opacity) { - if ( !rgbArray ) return "rgb('0,0,0')"; - - if (rgbArray.length == 4) { - rgbArray = angular.copy(rgbArray); - opacity ? rgbArray.pop() : opacity = rgbArray.pop(); - } - return opacity && (typeof opacity == 'number' || (typeof opacity == 'string' && opacity.length)) ? - 'rgba(' + rgbArray.join(',') + ',' + opacity + ')' : - 'rgb(' + rgbArray.join(',') + ')'; -} - - -(function(){ -angular.module("material.core").constant("$MD_THEME_CSS", "/* mixin definition ; sets LTR and RTL within the same style call */md-autocomplete.md-THEME_NAME-theme { background: '{{background-50}}'; } md-autocomplete.md-THEME_NAME-theme[disabled] { background: '{{background-100}}'; } md-autocomplete.md-THEME_NAME-theme button md-icon path { fill: '{{background-600}}'; } md-autocomplete.md-THEME_NAME-theme button:after { background: '{{background-600-0.3}}'; }.md-autocomplete-suggestions.md-THEME_NAME-theme { background: '{{background-50}}'; } .md-autocomplete-suggestions.md-THEME_NAME-theme li { color: '{{background-900}}'; } .md-autocomplete-suggestions.md-THEME_NAME-theme li .highlight { color: '{{background-600}}'; } .md-autocomplete-suggestions.md-THEME_NAME-theme li:hover, .md-autocomplete-suggestions.md-THEME_NAME-theme li.selected { background: '{{background-200}}'; }md-backdrop.md-opaque.md-THEME_NAME-theme { background-color: '{{foreground-4-0.5}}'; }md-bottom-sheet.md-THEME_NAME-theme { background-color: '{{background-50}}'; border-top-color: '{{background-300}}'; } md-bottom-sheet.md-THEME_NAME-theme.md-list md-list-item { color: '{{foreground-1}}'; } md-bottom-sheet.md-THEME_NAME-theme .md-subheader { background-color: '{{background-50}}'; } md-bottom-sheet.md-THEME_NAME-theme .md-subheader { color: '{{foreground-1}}'; }a.md-button.md-THEME_NAME-theme, .md-button.md-THEME_NAME-theme { border-radius: 3px; } a.md-button.md-THEME_NAME-theme:not([disabled]):hover, .md-button.md-THEME_NAME-theme:not([disabled]):hover { background-color: '{{background-500-0.2}}'; } a.md-button.md-THEME_NAME-theme:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme:not([disabled]).md-focused { background-color: '{{background-500-0.2}}'; } a.md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover, .md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover { background-color: transparent; } a.md-button.md-THEME_NAME-theme.md-fab, .md-button.md-THEME_NAME-theme.md-fab { border-radius: 50%; background-color: '{{accent-color}}'; color: '{{accent-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-fab md-icon, .md-button.md-THEME_NAME-theme.md-fab md-icon { color: '{{accent-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover { background-color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused { background-color: '{{accent-A700}}'; } a.md-button.md-THEME_NAME-theme.md-icon-button, .md-button.md-THEME_NAME-theme.md-icon-button { border-radius: 50%; } a.md-button.md-THEME_NAME-theme.md-primary, .md-button.md-THEME_NAME-theme.md-primary { color: '{{primary-color}}'; } a.md-button.md-THEME_NAME-theme.md-primary.md-raised, a.md-button.md-THEME_NAME-theme.md-primary.md-fab, .md-button.md-THEME_NAME-theme.md-primary.md-raised, .md-button.md-THEME_NAME-theme.md-primary.md-fab { color: '{{primary-contrast}}'; background-color: '{{primary-color}}'; } a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon { color: '{{primary-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover { background-color: '{{primary-color}}'; } a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused { background-color: '{{primary-600}}'; } a.md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon { color: '{{primary-color}}'; } a.md-button.md-THEME_NAME-theme.md-fab, .md-button.md-THEME_NAME-theme.md-fab { border-radius: 50%; background-color: '{{accent-color}}'; color: '{{accent-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]) .md-icon, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]) .md-icon { color: '{{accent-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover { background-color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused { background-color: '{{accent-A700}}'; } a.md-button.md-THEME_NAME-theme.md-raised, .md-button.md-THEME_NAME-theme.md-raised { color: '{{background-contrast}}'; background-color: '{{background-50}}'; } a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]) .md-icon, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]) .md-icon { color: '{{background-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover { background-color: '{{background-50}}'; } a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused { background-color: '{{background-200}}'; } a.md-button.md-THEME_NAME-theme.md-warn, .md-button.md-THEME_NAME-theme.md-warn { color: '{{warn-color}}'; } a.md-button.md-THEME_NAME-theme.md-warn.md-raised, a.md-button.md-THEME_NAME-theme.md-warn.md-fab, .md-button.md-THEME_NAME-theme.md-warn.md-raised, .md-button.md-THEME_NAME-theme.md-warn.md-fab { color: '{{warn-contrast}}'; background-color: '{{warn-color}}'; } a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon { color: '{{warn-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover { background-color: '{{warn-color}}'; } a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused { background-color: '{{warn-700}}'; } a.md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon { color: '{{warn-color}}'; } a.md-button.md-THEME_NAME-theme.md-accent, .md-button.md-THEME_NAME-theme.md-accent { color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme.md-accent.md-raised, a.md-button.md-THEME_NAME-theme.md-accent.md-fab, .md-button.md-THEME_NAME-theme.md-accent.md-raised, .md-button.md-THEME_NAME-theme.md-accent.md-fab { color: '{{accent-contrast}}'; background-color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon { color: '{{accent-contrast}}'; } a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover { background-color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused { background-color: '{{accent-700}}'; } a.md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon { color: '{{accent-color}}'; } a.md-button.md-THEME_NAME-theme[disabled], a.md-button.md-THEME_NAME-theme.md-raised[disabled], a.md-button.md-THEME_NAME-theme.md-fab[disabled], a.md-button.md-THEME_NAME-theme.md-accent[disabled], a.md-button.md-THEME_NAME-theme.md-warn[disabled], .md-button.md-THEME_NAME-theme[disabled], .md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled], .md-button.md-THEME_NAME-theme.md-accent[disabled], .md-button.md-THEME_NAME-theme.md-warn[disabled] { color: '{{foreground-3}}'; cursor: not-allowed; } a.md-button.md-THEME_NAME-theme[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon, .md-button.md-THEME_NAME-theme[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon { color: '{{foreground-3}}'; } a.md-button.md-THEME_NAME-theme.md-raised[disabled], a.md-button.md-THEME_NAME-theme.md-fab[disabled], .md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled] { background-color: '{{foreground-4}}'; } a.md-button.md-THEME_NAME-theme[disabled], .md-button.md-THEME_NAME-theme[disabled] { background-color: transparent; }md-card.md-THEME_NAME-theme { background-color: '{{background-color}}'; border-radius: 2px; } md-card.md-THEME_NAME-theme .md-card-image { border-radius: 2px 2px 0 0; }md-chips.md-THEME_NAME-theme .md-chips { box-shadow: 0 1px '{{background-300}}'; } md-chips.md-THEME_NAME-theme .md-chips.md-focused { box-shadow: 0 2px '{{primary-color}}'; }md-chips.md-THEME_NAME-theme .md-chip { background: '{{background-300}}'; color: '{{background-800}}'; } md-chips.md-THEME_NAME-theme .md-chip.md-focused { background: '{{primary-color}}'; color: '{{primary-contrast}}'; } md-chips.md-THEME_NAME-theme .md-chip.md-focused md-icon { color: '{{primary-contrast}}'; }md-chips.md-THEME_NAME-theme md-chip-remove .md-button md-icon path { fill: '{{background-500}}'; }.md-contact-suggestion span.md-contact-email { color: '{{background-400}}'; }md-content.md-THEME_NAME-theme { background-color: '{{background-color}}'; }md-checkbox.md-THEME_NAME-theme .md-ripple { color: '{{accent-600}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-ripple { color: '{{background-600}}'; }md-checkbox.md-THEME_NAME-theme.md-checked.md-focused .md-container:before { background-color: '{{accent-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme .md-icon { border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-icon { background-color: '{{accent-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-icon:after { border-color: '{{background-200}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ripple { color: '{{primary-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ripple { color: '{{background-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-icon { border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon { background-color: '{{primary-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked.md-focused .md-container:before { background-color: '{{primary-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon:after { border-color: '{{background-200}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ripple { color: '{{warn-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-icon { border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon { background-color: '{{warn-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked.md-focused:not([disabled]) .md-container:before { background-color: '{{warn-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon:after { border-color: '{{background-200}}'; }md-checkbox.md-THEME_NAME-theme[disabled] .md-icon { border-color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme[disabled].md-checked .md-icon { background-color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme[disabled] .md-label { color: '{{foreground-3}}'; }md-dialog.md-THEME_NAME-theme { border-radius: 4px; background-color: '{{background-color}}'; } md-dialog.md-THEME_NAME-theme.md-content-overflow .md-actions { border-top-color: '{{foreground-4}}'; }md-divider.md-THEME_NAME-theme { border-top-color: '{{foreground-4}}'; }md-icon.md-THEME_NAME-theme { color: '{{foreground-2}}'; } md-icon.md-THEME_NAME-theme.md-primary { color: '{{primary-color}}'; } md-icon.md-THEME_NAME-theme.md-accent { color: '{{accent-color}}'; } md-icon.md-THEME_NAME-theme.md-warn { color: '{{warn-color}}'; }md-input-container.md-THEME_NAME-theme .md-input { color: '{{foreground-1}}'; border-color: '{{foreground-4}}'; text-shadow: '{{foreground-shadow}}'; } md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder, md-input-container.md-THEME_NAME-theme .md-input::-moz-placeholder, md-input-container.md-THEME_NAME-theme .md-input:-moz-placeholder, md-input-container.md-THEME_NAME-theme .md-input:-ms-input-placeholder { color: '{{foreground-3}}'; }md-input-container.md-THEME_NAME-theme > md-icon { color: '{{foreground-1}}'; }md-input-container.md-THEME_NAME-theme label, md-input-container.md-THEME_NAME-theme .md-placeholder { text-shadow: '{{foreground-shadow}}'; color: '{{foreground-3}}'; }md-input-container.md-THEME_NAME-theme ng-messages, md-input-container.md-THEME_NAME-theme [ng-message], md-input-container.md-THEME_NAME-theme [data-ng-message], md-input-container.md-THEME_NAME-theme [x-ng-message] { color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-has-value label { color: '{{foreground-2}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused .md-input { border-color: '{{primary-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused label { color: '{{primary-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused md-icon { color: '{{primary-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent .md-input { border-color: '{{accent-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent label { color: '{{accent-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn .md-input { border-color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn label { color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input { border-color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme.md-input-invalid.md-input-focused label { color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme.md-input-invalid ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid data-ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid x-ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid [ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid [data-ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid [x-ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid .md-char-counter { color: '{{warn-500}}'; }md-input-container.md-THEME_NAME-theme .md-input[disabled], [disabled] md-input-container.md-THEME_NAME-theme .md-input { border-bottom-color: transparent; color: '{{foreground-3}}'; background-image: linear-gradient(to right, '{{foreground-3}}' 0%, '{{foreground-3}}' 33%, transparent 0%); background-image: -ms-linear-gradient(left, transparent 0%, '{{foreground-3}}' 100%); }md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h3, md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h4, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h3, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h4 { color: '{{foreground-1}}'; }md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text p, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text p { color: '{{foreground-2}}'; }md-list.md-THEME_NAME-theme .md-proxy-focus.md-focused div.md-no-style { background-color: '{{background-100}}'; }md-list.md-THEME_NAME-theme md-list-item > md-icon { color: '{{foreground-2}}'; } md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight { color: '{{primary-color}}'; } md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight.md-accent { color: '{{accent-color}}'; }md-list.md-THEME_NAME-theme md-list-item button { background-color: '{{background-color}}'; } md-list.md-THEME_NAME-theme md-list-item button.md-button:not([disabled]):hover { background-color: '{{background-color}}'; }md-progress-circular.md-THEME_NAME-theme { background-color: transparent; } md-progress-circular.md-THEME_NAME-theme .md-inner .md-gap { border-top-color: '{{primary-color}}'; border-bottom-color: '{{primary-color}}'; } md-progress-circular.md-THEME_NAME-theme .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme .md-inner .md-right .md-half-circle { border-top-color: '{{primary-color}}'; } md-progress-circular.md-THEME_NAME-theme .md-inner .md-right .md-half-circle { border-right-color: '{{primary-color}}'; } md-progress-circular.md-THEME_NAME-theme .md-inner .md-left .md-half-circle { border-left-color: '{{primary-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-gap { border-top-color: '{{warn-color}}'; border-bottom-color: '{{warn-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-right .md-half-circle { border-top-color: '{{warn-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-right .md-half-circle { border-right-color: '{{warn-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-left .md-half-circle { border-left-color: '{{warn-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-gap { border-top-color: '{{accent-color}}'; border-bottom-color: '{{accent-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-right .md-half-circle { border-top-color: '{{accent-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-right .md-half-circle { border-right-color: '{{accent-color}}'; } md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-left .md-half-circle { border-left-color: '{{accent-color}}'; }md-progress-linear.md-THEME_NAME-theme .md-container { background-color: '{{primary-100}}'; }md-progress-linear.md-THEME_NAME-theme .md-bar { background-color: '{{primary-color}}'; }md-progress-linear.md-THEME_NAME-theme.md-warn .md-container { background-color: '{{warn-100}}'; }md-progress-linear.md-THEME_NAME-theme.md-warn .md-bar { background-color: '{{warn-color}}'; }md-progress-linear.md-THEME_NAME-theme.md-accent .md-container { background-color: '{{accent-100}}'; }md-progress-linear.md-THEME_NAME-theme.md-accent .md-bar { background-color: '{{accent-color}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-bar1 { background-color: '{{warn-100}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-dashed:before { background: radial-gradient('{{warn-100}}' 0%, '{{warn-100}}' 16%, transparent 42%); }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-bar1 { background-color: '{{accent-100}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-dashed:before { background: radial-gradient('{{accent-100}}' 0%, '{{accent-100}}' 16%, transparent 42%); }md-radio-button.md-THEME_NAME-theme .md-off { border-color: '{{foreground-2}}'; }md-radio-button.md-THEME_NAME-theme .md-on { background-color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme.md-checked .md-off { border-color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme.md-checked .md-ink-ripple { color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme .md-container .md-ripple { color: '{{accent-600}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-on { background-color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off { border-color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple { color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple { color: '{{primary-600}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-on { background-color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off { border-color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple { color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple { color: '{{warn-600}}'; }md-radio-group.md-THEME_NAME-theme[disabled], md-radio-button.md-THEME_NAME-theme[disabled] { color: '{{foreground-3}}'; } md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-off, md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-off { border-color: '{{foreground-3}}'; } md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-on, md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-on { border-color: '{{foreground-3}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked .md-container:before { background-color: '{{accent-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked:not([disabled]).md-primary .md-container:before { background-color: '{{primary-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-primary .md-container:before { background-color: '{{warn-color-0.26}}'; }md-sidenav.md-THEME_NAME-theme { background-color: '{{background-color}}'; }md-select.md-THEME_NAME-theme.ng-invalid.ng-dirty .md-select-label { color: '{{warn-500}}' !important; border-bottom-color: '{{warn-500}}' !important; }md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-label { border-bottom-color: '{{primary-color}}'; color: '{{ foreground-1 }}'; } md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-label.md-placeholder { color: '{{ foreground-1 }}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-label { border-bottom-color: '{{accent-color}}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-label { border-bottom-color: '{{warn-color}}'; }md-select.md-THEME_NAME-theme[disabled] .md-select-label { color: '{{foreground-3}}'; } md-select.md-THEME_NAME-theme[disabled] .md-select-label.md-placeholder { color: '{{foreground-3}}'; }md-select.md-THEME_NAME-theme .md-select-label { border-bottom-color: '{{foreground-4}}'; } md-select.md-THEME_NAME-theme .md-select-label.md-placeholder { color: '{{foreground-2}}'; }md-select-menu.md-THEME_NAME-theme md-optgroup { color: '{{foreground-2}}'; } md-select-menu.md-THEME_NAME-theme md-optgroup md-option { color: '{{foreground-1}}'; }md-select-menu.md-THEME_NAME-theme md-option[selected] { color: '{{primary-500}}'; } md-select-menu.md-THEME_NAME-theme md-option[selected]:focus { color: '{{primary-600}}'; } md-select-menu.md-THEME_NAME-theme md-option[selected].md-accent { color: '{{accent-500}}'; } md-select-menu.md-THEME_NAME-theme md-option[selected].md-accent:focus { color: '{{accent-600}}'; }md-select-menu.md-THEME_NAME-theme md-option:focus:not([selected]) { background: '{{background-200}}'; }md-slider.md-THEME_NAME-theme .md-track { background-color: '{{foreground-3}}'; }md-slider.md-THEME_NAME-theme .md-track-ticks { background-color: '{{foreground-4}}'; }md-slider.md-THEME_NAME-theme .md-focus-thumb { background-color: '{{foreground-2}}'; }md-slider.md-THEME_NAME-theme .md-focus-ring { border-color: '{{foreground-4}}'; }md-slider.md-THEME_NAME-theme .md-disabled-thumb { border-color: '{{background-color}}'; }md-slider.md-THEME_NAME-theme.md-min .md-thumb:after { background-color: '{{background-color}}'; }md-slider.md-THEME_NAME-theme .md-track.md-track-fill { background-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-thumb:after { border-color: '{{accent-color}}'; background-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-sign { background-color: '{{accent-color}}'; } md-slider.md-THEME_NAME-theme .md-sign:after { border-top-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-thumb-text { color: '{{accent-contrast}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-track.md-track-fill { background-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-thumb:after { border-color: '{{warn-color}}'; background-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-sign { background-color: '{{warn-color}}'; } md-slider.md-THEME_NAME-theme.md-warn .md-sign:after { border-top-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-thumb-text { color: '{{warn-contrast}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-track.md-track-fill { background-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-thumb:after { border-color: '{{primary-color}}'; background-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-sign { background-color: '{{primary-color}}'; } md-slider.md-THEME_NAME-theme.md-primary .md-sign:after { border-top-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-thumb-text { color: '{{primary-contrast}}'; }md-slider.md-THEME_NAME-theme[disabled] .md-thumb:after { border-color: '{{foreground-3}}'; }md-slider.md-THEME_NAME-theme[disabled]:not(.md-min) .md-thumb:after { background-color: '{{foreground-3}}'; }.md-subheader.md-THEME_NAME-theme { color: '{{ foreground-2-0.23 }}'; background-color: '{{background-color}}'; } .md-subheader.md-THEME_NAME-theme.md-primary { color: '{{primary-color}}'; } .md-subheader.md-THEME_NAME-theme.md-accent { color: '{{accent-color}}'; } .md-subheader.md-THEME_NAME-theme.md-warn { color: '{{warn-color}}'; }md-switch.md-THEME_NAME-theme .md-thumb { background-color: '{{background-50}}'; }md-switch.md-THEME_NAME-theme .md-bar { background-color: '{{background-500}}'; }md-switch.md-THEME_NAME-theme.md-checked .md-thumb { background-color: '{{accent-color}}'; }md-switch.md-THEME_NAME-theme.md-checked .md-bar { background-color: '{{accent-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-focused .md-thumb:before { background-color: '{{accent-color-0.26}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-thumb { background-color: '{{primary-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-bar { background-color: '{{primary-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary.md-focused .md-thumb:before { background-color: '{{primary-color-0.26}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-thumb { background-color: '{{warn-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-bar { background-color: '{{warn-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn.md-focused .md-thumb:before { background-color: '{{warn-color-0.26}}'; }md-switch.md-THEME_NAME-theme[disabled] .md-thumb { background-color: '{{background-400}}'; }md-switch.md-THEME_NAME-theme[disabled] .md-bar { background-color: '{{foreground-4}}'; }md-tabs.md-THEME_NAME-theme md-tabs-wrapper { background-color: transparent; border-color: '{{foreground-4}}'; }md-tabs.md-THEME_NAME-theme .md-paginator md-icon { color: '{{primary-color}}'; }md-tabs.md-THEME_NAME-theme md-ink-bar { color: '{{accent-color}}'; background: '{{accent-color}}'; }md-tabs.md-THEME_NAME-theme .md-tab { color: '{{foreground-2}}'; } md-tabs.md-THEME_NAME-theme .md-tab[disabled] { color: '{{foreground-3}}'; } md-tabs.md-THEME_NAME-theme .md-tab.md-active, md-tabs.md-THEME_NAME-theme .md-tab.md-focused { color: '{{primary-color}}'; } md-tabs.md-THEME_NAME-theme .md-tab.md-focused { background: '{{primary-color-0.1}}'; } md-tabs.md-THEME_NAME-theme .md-tab .md-ripple-container { color: '{{accent-100}}'; }md-tabs.md-THEME_NAME-theme.md-accent md-tabs-wrapper { background-color: '{{accent-color}}'; }md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]) { color: '{{accent-100}}'; } md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-focused { color: '{{accent-contrast}}'; } md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-focused { background: '{{accent-contrast-0.1}}'; }md-tabs.md-THEME_NAME-theme.md-accent md-ink-bar { color: '{{primary-600-1}}'; background: '{{primary-600-1}}'; }md-tabs.md-THEME_NAME-theme.md-primary md-tabs-wrapper { background-color: '{{primary-color}}'; }md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]) { color: '{{primary-100}}'; } md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-focused { color: '{{primary-contrast}}'; } md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-focused { background: '{{primary-contrast-0.1}}'; }md-tabs.md-THEME_NAME-theme.md-warn md-tabs-wrapper { background-color: '{{warn-color}}'; }md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]) { color: '{{warn-100}}'; } md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-focused { color: '{{warn-contrast}}'; } md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-focused { background: '{{warn-contrast-0.1}}'; }md-toolbar > md-tabs.md-THEME_NAME-theme md-tabs-wrapper { background-color: '{{primary-color}}'; }md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) { color: '{{primary-100}}'; } md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { color: '{{primary-contrast}}'; } md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { background: '{{primary-contrast-0.1}}'; }md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tabs-wrapper { background-color: '{{accent-color}}'; }md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) { color: '{{accent-100}}'; } md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { color: '{{accent-contrast}}'; } md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { background: '{{accent-contrast-0.1}}'; }md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-ink-bar { color: '{{primary-600-1}}'; background: '{{primary-600-1}}'; }md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tabs-wrapper { background-color: '{{warn-color}}'; }md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) { color: '{{warn-100}}'; } md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { color: '{{warn-contrast}}'; } md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused { background: '{{warn-contrast-0.1}}'; }md-toast.md-THEME_NAME-theme { background-color: #323232; color: '{{background-50}}'; } md-toast.md-THEME_NAME-theme .md-button { color: '{{background-50}}'; } md-toast.md-THEME_NAME-theme .md-button.md-highlight { color: '{{primary-A200}}'; } md-toast.md-THEME_NAME-theme .md-button.md-highlight.md-accent { color: '{{accent-A200}}'; } md-toast.md-THEME_NAME-theme .md-button.md-highlight.md-warn { color: '{{warn-A200}}'; }md-toolbar.md-THEME_NAME-theme { background-color: '{{primary-color}}'; color: '{{primary-contrast}}'; } md-toolbar.md-THEME_NAME-theme md-icon { color: '{{primary-contrast}}'; } md-toolbar.md-THEME_NAME-theme .md-button { color: '{{primary-contrast}}'; } md-toolbar.md-THEME_NAME-theme.md-accent { background-color: '{{accent-color}}'; color: '{{accent-contrast}}'; } md-toolbar.md-THEME_NAME-theme.md-warn { background-color: '{{warn-color}}'; color: '{{warn-contrast}}'; }md-tooltip.md-THEME_NAME-theme { color: '{{background-A100}}'; } md-tooltip.md-THEME_NAME-theme .md-background { background-color: '{{foreground-2}}'; }"); -})(); - - -})(window, window.angular);
\ No newline at end of file |