rails-angular-material 0.10.0 → 0.10.1.pre.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58c390d10897725e0d6b2ce4c7025a33f62a55aa
4
- data.tar.gz: 0934c050f21161d765a06c5f7d406a93d937983c
3
+ metadata.gz: baac433d50fdf33bb8380397d0cecaaa1427517e
4
+ data.tar.gz: 52f5aaf087566cf03e85a9b1ff196659fdaef702
5
5
  SHA512:
6
- metadata.gz: 848acc5a7f82c5e57e2c19a4687369796207d7816d07779af93f7577d583a7eeb7060d256e10d9c93b1f815fb9962d248434e83b8f5bbc2dcb2e05add3403946
7
- data.tar.gz: 9a3cc7383f84a6f44f96c9dd37ccd8d23305eca5355a7e26aabfa4913ea8e778fa527c0d7f449bed9b87dd974b6f60ea7c810c11e1f7f236c524707935c71043
6
+ metadata.gz: 25dbd573aeec56e75aa26b566353962288f123449aca40c04f4123a3f161395d4631ea4ea9d09e880826d0efc34c72b188417380b0666c025c1cc1d118c066b5
7
+ data.tar.gz: 715190b946143fea1769b8ec4bde0af9abeeeaa8494ece92513a81024b18ba3b8717eae90ac3d166e584a968178ae99b618e7eb49554c9891b79b2102a17ef62
data/README.md CHANGED
@@ -23,4 +23,4 @@ If you desire to require minified AngularMaterial files, add the following:
23
23
 
24
24
  ## Versioning
25
25
 
26
- Current version of AngularMaterial - 0.10.0-354fee2
26
+ Current version of AngularMaterial - 0.10.1-rc1
@@ -1,3 +1,3 @@
1
1
  module AngularMaterialRails
2
- VERSION = "0.10.0"
2
+ VERSION = "0.10.1-rc1"
3
3
  end
@@ -2,7 +2,7 @@
2
2
  * Angular Material Design
3
3
  * https://github.com/angular/material
4
4
  * @license MIT
5
- * v0.10.0
5
+ * v0.10.1-rc1
6
6
  */
7
7
  (function( window, angular, undefined ){
8
8
  "use strict";
@@ -10,7 +10,7 @@
10
10
  (function(){
11
11
  "use strict";
12
12
 
13
- angular.module('ngMaterial', ["ng","ngAnimate","ngAria","material.core","material.core.gestures","material.core.theming.palette","material.core.theming","material.components.autocomplete","material.components.backdrop","material.components.bottomSheet","material.components.card","material.components.button","material.components.checkbox","material.components.content","material.components.chips","material.components.dialog","material.components.divider","material.components.fabActions","material.components.fabSpeedDial","material.components.fabToolbar","material.components.fabTrigger","material.components.gridList","material.components.icon","material.components.input","material.components.list","material.components.menu","material.components.progressCircular","material.components.progressLinear","material.components.radioButton","material.components.select","material.components.sidenav","material.components.slider","material.components.sticky","material.components.subheader","material.components.swipe","material.components.switch","material.components.tabs","material.components.toast","material.components.toolbar","material.components.tooltip","material.components.whiteframe"]);
13
+ angular.module('ngMaterial', ["ng","ngAnimate","ngAria","material.core","material.core.gestures","material.core.theming.palette","material.core.theming","material.components.autocomplete","material.components.backdrop","material.components.bottomSheet","material.components.button","material.components.card","material.components.checkbox","material.components.chips","material.components.content","material.components.dialog","material.components.divider","material.components.fabActions","material.components.fabSpeedDial","material.components.fabToolbar","material.components.fabTrigger","material.components.gridList","material.components.icon","material.components.input","material.components.list","material.components.menu","material.components.progressCircular","material.components.progressLinear","material.components.radioButton","material.components.select","material.components.sidenav","material.components.slider","material.components.sticky","material.components.subheader","material.components.swipe","material.components.switch","material.components.tabs","material.components.toast","material.components.toolbar","material.components.tooltip","material.components.virtualRepeat","material.components.whiteframe"]);
14
14
  })();
15
15
  (function(){
16
16
  "use strict";
@@ -111,11 +111,11 @@ function MdConstantFactory($$rAF, $sniffer) {
111
111
  ANIMATION_DIRECTION: vendorProperty('animationDirection')
112
112
  },
113
113
  MEDIA: {
114
- 'sm': '(max-width: 600px)',
114
+ 'sm': '(max-width: 599px)',
115
115
  'gt-sm': '(min-width: 600px)',
116
- 'md': '(min-width: 600px) and (max-width: 960px)',
116
+ 'md': '(min-width: 600px) and (max-width: 959px)',
117
117
  'gt-md': '(min-width: 960px)',
118
- 'lg': '(min-width: 960px) and (max-width: 1200px)',
118
+ 'lg': '(min-width: 960px) and (max-width: 1199px)',
119
119
  'gt-lg': '(min-width: 1200px)'
120
120
  },
121
121
  MEDIA_PRIORITY: [
@@ -507,349 +507,365 @@ mdMediaFactory.$inject = ["$mdConstant", "$rootScope", "$window"];
507
507
  var nextUniqueId = 0;
508
508
 
509
509
  angular.module('material.core')
510
- .factory('$mdUtil', ["$cacheFactory", "$document", "$timeout", "$q", "$window", "$mdConstant", function($cacheFactory, $document, $timeout, $q, $window, $mdConstant) {
511
- var Util;
510
+ .factory('$mdUtil', ["$cacheFactory", "$document", "$timeout", "$q", "$window", "$mdConstant", function ($cacheFactory, $document, $timeout, $q, $window, $mdConstant) {
511
+ var Util;
512
512
 
513
- function getNode(el) {
514
- return el[0] || el;
515
- }
513
+ function getNode(el) {
514
+ return el[0] || el;
515
+ }
516
516
 
517
- return Util = {
518
- now: window.performance ?
519
- angular.bind(window.performance, window.performance.now) :
520
- Date.now,
517
+ return Util = {
518
+ now: window.performance ?
519
+ angular.bind(window.performance, window.performance.now) :
520
+ Date.now,
521
521
 
522
- clientRect: function(element, offsetParent, isOffsetRect) {
523
- var node = getNode(element);
524
- offsetParent = getNode(offsetParent || node.offsetParent || document.body);
525
- var nodeRect = node.getBoundingClientRect();
522
+ clientRect: function (element, offsetParent, isOffsetRect) {
523
+ var node = getNode(element);
524
+ offsetParent = getNode(offsetParent || node.offsetParent || document.body);
525
+ var nodeRect = node.getBoundingClientRect();
526
526
 
527
- // The user can ask for an offsetRect: a rect relative to the offsetParent,
528
- // or a clientRect: a rect relative to the page
529
- var offsetRect = isOffsetRect ?
530
- offsetParent.getBoundingClientRect() :
531
- { left: 0, top: 0, width: 0, height: 0 };
532
- return {
533
- left: nodeRect.left - offsetRect.left,
534
- top: nodeRect.top - offsetRect.top,
535
- width: nodeRect.width,
536
- height: nodeRect.height
537
- };
538
- },
539
- offsetRect: function(element, offsetParent) {
540
- return Util.clientRect(element, offsetParent, true);
541
- },
527
+ // The user can ask for an offsetRect: a rect relative to the offsetParent,
528
+ // or a clientRect: a rect relative to the page
529
+ var offsetRect = isOffsetRect ?
530
+ offsetParent.getBoundingClientRect() :
531
+ {left: 0, top: 0, width: 0, height: 0};
532
+ return {
533
+ left: nodeRect.left - offsetRect.left,
534
+ top: nodeRect.top - offsetRect.top,
535
+ width: nodeRect.width,
536
+ height: nodeRect.height
537
+ };
538
+ },
539
+ offsetRect: function (element, offsetParent) {
540
+ return Util.clientRect(element, offsetParent, true);
541
+ },
542
542
 
543
- // Annoying method to copy nodes to an array, thanks to IE
544
- nodesToArray: function (nodes) {
545
- var results = [];
546
- for (var i = 0; i < nodes.length; ++i) {
547
- results.push(nodes.item(i));
548
- }
549
- return results;
550
- },
543
+ // Annoying method to copy nodes to an array, thanks to IE
544
+ nodesToArray: function (nodes) {
545
+ nodes = nodes || [ ];
551
546
 
552
- // Disables scroll around the passed element.
553
- disableScrollAround: function(element) {
554
- if (Util.disableScrollAround._enableScrolling) return Util.disableScrollAround._enableScrolling;
555
- element = angular.element(element);
556
- var body = $document[0].body,
547
+ var results = [];
548
+ for (var i = 0; i < nodes.length; ++i) {
549
+ results.push(nodes.item(i));
550
+ }
551
+ return results;
552
+ },
553
+
554
+ // Disables scroll around the passed element.
555
+ disableScrollAround: function (element) {
556
+ Util.disableScrollAround._count = Util.disableScrollAround._count || 0;
557
+ ++Util.disableScrollAround._count;
558
+ if (Util.disableScrollAround._enableScrolling) return Util.disableScrollAround._enableScrolling;
559
+ element = angular.element(element);
560
+ var body = $document[0].body,
557
561
  restoreBody = disableBodyScroll(),
558
562
  restoreElement = disableElementScroll();
559
563
 
560
- return Util.disableScrollAround._enableScrolling = function () {
561
- restoreBody();
562
- restoreElement();
563
- delete Util.disableScrollAround._enableScrolling;
564
- };
564
+ return Util.disableScrollAround._enableScrolling = function () {
565
+ if (!--Util.disableScrollAround._count) {
566
+ restoreBody();
567
+ restoreElement();
568
+ delete Util.disableScrollAround._enableScrolling;
569
+ }
570
+ };
565
571
 
566
- // Creates a virtual scrolling mask to absorb touchmove, keyboard, scrollbar clicking, and wheel events
567
- function disableElementScroll() {
568
- var zIndex = $window.getComputedStyle(element[0]).zIndex - 1;
569
- if (isNaN(zIndex)) zIndex = 99;
570
- var scrollMask = angular.element(
572
+ // Creates a virtual scrolling mask to absorb touchmove, keyboard, scrollbar clicking, and wheel events
573
+ function disableElementScroll() {
574
+ var zIndex = 50;
575
+ var scrollMask = angular.element(
571
576
  '<div class="md-scroll-mask" style="z-index: ' + zIndex + '">' +
572
577
  ' <div class="md-scroll-mask-bar"></div>' +
573
578
  '</div>');
574
- body.appendChild(scrollMask[0]);
575
-
576
- scrollMask.on('wheel', preventDefault);
577
- scrollMask.on('touchmove', preventDefault);
578
- $document.on('keydown', disableKeyNav);
579
-
580
- return function restoreScroll () {
581
- scrollMask.off('wheel');
582
- scrollMask.off('touchmove');
583
- scrollMask[0].parentNode.removeChild(scrollMask[0]);
584
- $document.off('keydown', disableKeyNav);
585
- delete Util.disableScrollAround._enableScrolling;
586
- };
579
+ body.appendChild(scrollMask[0]);
580
+
581
+ scrollMask.on('wheel', preventDefault);
582
+ scrollMask.on('touchmove', preventDefault);
583
+ $document.on('keydown', disableKeyNav);
584
+
585
+ return function restoreScroll() {
586
+ scrollMask.off('wheel');
587
+ scrollMask.off('touchmove');
588
+ scrollMask[0].parentNode.removeChild(scrollMask[0]);
589
+ $document.off('keydown', disableKeyNav);
590
+ delete Util.disableScrollAround._enableScrolling;
591
+ };
587
592
 
588
- // Prevent keypresses from elements inside the body
589
- // used to stop the keypresses that could cause the page to scroll
590
- // (arrow keys, spacebar, tab, etc).
591
- function disableKeyNav(e) {
592
- //-- temporarily removed this logic, will possibly re-add at a later date
593
- return;
594
- if (!element[0].contains(e.target)) {
595
- e.preventDefault();
596
- e.stopImmediatePropagation();
593
+ // Prevent keypresses from elements inside the body
594
+ // used to stop the keypresses that could cause the page to scroll
595
+ // (arrow keys, spacebar, tab, etc).
596
+ function disableKeyNav(e) {
597
+ //-- temporarily removed this logic, will possibly re-add at a later date
598
+ return;
599
+ if (!element[0].contains(e.target)) {
600
+ e.preventDefault();
601
+ e.stopImmediatePropagation();
602
+ }
597
603
  }
598
- }
599
604
 
600
- function preventDefault(e) {
601
- e.preventDefault();
605
+ function preventDefault(e) {
606
+ e.preventDefault();
607
+ }
602
608
  }
603
- }
604
609
 
605
- // Converts the body to a position fixed block and translate it to the proper scroll
606
- // position
607
- function disableBodyScroll() {
608
- var restoreStyle = body.getAttribute('style') || '';
609
- var scrollOffset = body.scrollTop + body.parentElement.scrollTop;
610
- var clientWidth = body.clientWidth;
610
+ // Converts the body to a position fixed block and translate it to the proper scroll
611
+ // position
612
+ function disableBodyScroll() {
613
+ var htmlNode = body.parentNode;
614
+ var restoreHtmlStyle = htmlNode.getAttribute('style') || '';
615
+ var restoreBodyStyle = body.getAttribute('style') || '';
616
+ var scrollOffset = body.scrollTop + body.parentElement.scrollTop;
617
+ var clientWidth = body.clientWidth;
618
+
619
+ if (body.scrollHeight > body.clientHeight) {
620
+ applyStyles(body, {
621
+ position: 'fixed',
622
+ width: '100%',
623
+ top: -scrollOffset + 'px'
624
+ });
611
625
 
612
- applyStyles(body, {
613
- position: 'fixed',
614
- width: '100%',
615
- overflowY: 'scroll',
616
- top: -scrollOffset + 'px'
617
- });
626
+ applyStyles(htmlNode, {
627
+ overflowY: 'scroll'
628
+ });
629
+ }
618
630
 
619
- if (body.clientWidth < clientWidth) applyStyles(body, { overflow: 'auto' });
620
631
 
621
- return function restoreScroll() {
622
- body.setAttribute('style', restoreStyle);
623
- body.scrollTop = scrollOffset;
624
- };
625
- }
632
+ if (body.clientWidth < clientWidth) applyStyles(body, {overflow: 'hidden'});
626
633
 
627
- function applyStyles (el, styles) {
628
- for (var key in styles) {
629
- el.style[key] = styles[key];
634
+ return function restoreScroll() {
635
+ body.setAttribute('style', restoreBodyStyle);
636
+ htmlNode.setAttribute('style', restoreHtmlStyle);
637
+ body.scrollTop = scrollOffset;
638
+ };
630
639
  }
631
- }
632
- },
633
- enableScrolling: function () {
634
- var method = this.disableScrollAround._enableScrolling;
635
- method && method();
636
- },
637
- floatingScrollbars: function() {
638
- if (this.floatingScrollbars.cached === undefined) {
639
- var tempNode = angular.element('<div style="width: 100%; z-index: -1; position: absolute; height: 35px; overflow-y: scroll"><div style="height: 60;"></div></div>');
640
- $document[0].body.appendChild(tempNode[0]);
641
- this.floatingScrollbars.cached = (tempNode[0].offsetWidth == tempNode[0].childNodes[0].offsetWidth);
642
- tempNode.remove();
643
- }
644
- return this.floatingScrollbars.cached;
645
- },
646
640
 
647
- // Mobile safari only allows you to set focus in click event listeners...
648
- forceFocus: function(element) {
649
- var node = element[0] || element;
650
-
651
- document.addEventListener('click', function focusOnClick(ev) {
652
- if (ev.target === node && ev.$focus) {
653
- node.focus();
654
- ev.stopImmediatePropagation();
655
- ev.preventDefault();
656
- node.removeEventListener('click', focusOnClick);
641
+ function applyStyles(el, styles) {
642
+ for (var key in styles) {
643
+ el.style[key] = styles[key];
644
+ }
657
645
  }
658
- }, true);
646
+ },
647
+ enableScrolling: function () {
648
+ var method = this.disableScrollAround._enableScrolling;
649
+ method && method();
650
+ },
651
+ floatingScrollbars: function () {
652
+ if (this.floatingScrollbars.cached === undefined) {
653
+ var tempNode = angular.element('<div style="width: 100%; z-index: -1; position: absolute; height: 35px; overflow-y: scroll"><div style="height: 60;"></div></div>');
654
+ $document[0].body.appendChild(tempNode[0]);
655
+ this.floatingScrollbars.cached = (tempNode[0].offsetWidth == tempNode[0].childNodes[0].offsetWidth);
656
+ tempNode.remove();
657
+ }
658
+ return this.floatingScrollbars.cached;
659
+ },
659
660
 
660
- var newEvent = document.createEvent('MouseEvents');
661
- newEvent.initMouseEvent('click', false, true, window, {}, 0, 0, 0, 0,
662
- false, false, false, false, 0, null);
663
- newEvent.$material = true;
664
- newEvent.$focus = true;
665
- node.dispatchEvent(newEvent);
666
- },
661
+ // Mobile safari only allows you to set focus in click event listeners...
662
+ forceFocus: function (element) {
663
+ var node = element[0] || element;
664
+
665
+ document.addEventListener('click', function focusOnClick(ev) {
666
+ if (ev.target === node && ev.$focus) {
667
+ node.focus();
668
+ ev.stopImmediatePropagation();
669
+ ev.preventDefault();
670
+ node.removeEventListener('click', focusOnClick);
671
+ }
672
+ }, true);
673
+
674
+ var newEvent = document.createEvent('MouseEvents');
675
+ newEvent.initMouseEvent('click', false, true, window, {}, 0, 0, 0, 0,
676
+ false, false, false, false, 0, null);
677
+ newEvent.$material = true;
678
+ newEvent.$focus = true;
679
+ node.dispatchEvent(newEvent);
680
+ },
667
681
 
668
- transitionEndPromise: function(element, opts) {
669
- opts = opts || {};
670
- var deferred = $q.defer();
671
- element.on($mdConstant.CSS.TRANSITIONEND, finished);
672
- function finished(ev) {
673
- // Make sure this transitionend didn't bubble up from a child
674
- if (!ev || ev.target === element[0]) {
675
- element.off($mdConstant.CSS.TRANSITIONEND, finished);
676
- deferred.resolve();
682
+ transitionEndPromise: function (element, opts) {
683
+ opts = opts || {};
684
+ var deferred = $q.defer();
685
+ element.on($mdConstant.CSS.TRANSITIONEND, finished);
686
+ function finished(ev) {
687
+ // Make sure this transitionend didn't bubble up from a child
688
+ if (!ev || ev.target === element[0]) {
689
+ element.off($mdConstant.CSS.TRANSITIONEND, finished);
690
+ deferred.resolve();
691
+ }
677
692
  }
678
- }
679
- if (opts.timeout) $timeout(finished, opts.timeout);
680
- return deferred.promise;
681
- },
682
693
 
683
- fakeNgModel: function() {
684
- return {
685
- $fake: true,
686
- $setTouched: angular.noop,
687
- $setViewValue: function(value) {
688
- this.$viewValue = value;
689
- this.$render(value);
690
- this.$viewChangeListeners.forEach(function(cb) { cb(); });
691
- },
692
- $isEmpty: function(value) {
693
- return ('' + value).length === 0;
694
- },
695
- $parsers: [],
696
- $formatters: [],
697
- $viewChangeListeners: [],
698
- $render: angular.noop
699
- };
700
- },
694
+ if (opts.timeout) $timeout(finished, opts.timeout);
695
+ return deferred.promise;
696
+ },
701
697
 
702
- // Returns a function, that, as long as it continues to be invoked, will not
703
- // be triggered. The function will be called after it stops being called for
704
- // N milliseconds.
705
- // @param wait Integer value of msecs to delay (since last debounce reset); default value 10 msecs
706
- // @param invokeApply should the $timeout trigger $digest() dirty checking
707
- debounce: function (func, wait, scope, invokeApply) {
708
- var timer;
698
+ fakeNgModel: function () {
699
+ return {
700
+ $fake: true,
701
+ $setTouched: angular.noop,
702
+ $setViewValue: function (value) {
703
+ this.$viewValue = value;
704
+ this.$render(value);
705
+ this.$viewChangeListeners.forEach(function (cb) {
706
+ cb();
707
+ });
708
+ },
709
+ $isEmpty: function (value) {
710
+ return ('' + value).length === 0;
711
+ },
712
+ $parsers: [],
713
+ $formatters: [],
714
+ $viewChangeListeners: [],
715
+ $render: angular.noop
716
+ };
717
+ },
709
718
 
710
- return function debounced() {
711
- var context = scope,
712
- args = Array.prototype.slice.call(arguments);
719
+ // Returns a function, that, as long as it continues to be invoked, will not
720
+ // be triggered. The function will be called after it stops being called for
721
+ // N milliseconds.
722
+ // @param wait Integer value of msecs to delay (since last debounce reset); default value 10 msecs
723
+ // @param invokeApply should the $timeout trigger $digest() dirty checking
724
+ debounce: function (func, wait, scope, invokeApply) {
725
+ var timer;
713
726
 
714
- $timeout.cancel(timer);
715
- timer = $timeout(function() {
727
+ return function debounced() {
728
+ var context = scope,
729
+ args = Array.prototype.slice.call(arguments);
716
730
 
717
- timer = undefined;
718
- func.apply(context, args);
731
+ $timeout.cancel(timer);
732
+ timer = $timeout(function () {
719
733
 
720
- }, wait || 10, invokeApply );
721
- };
722
- },
734
+ timer = undefined;
735
+ func.apply(context, args);
723
736
 
724
- // Returns a function that can only be triggered every `delay` milliseconds.
725
- // In other words, the function will not be called unless it has been more
726
- // than `delay` milliseconds since the last call.
727
- throttle: function throttle(func, delay) {
728
- var recent;
729
- return function throttled() {
730
- var context = this;
731
- var args = arguments;
732
- var now = Util.now();
737
+ }, wait || 10, invokeApply);
738
+ };
739
+ },
733
740
 
734
- if (!recent || (now - recent > delay)) {
735
- func.apply(context, args);
736
- recent = now;
737
- }
738
- };
739
- },
741
+ // Returns a function that can only be triggered every `delay` milliseconds.
742
+ // In other words, the function will not be called unless it has been more
743
+ // than `delay` milliseconds since the last call.
744
+ throttle: function throttle(func, delay) {
745
+ var recent;
746
+ return function throttled() {
747
+ var context = this;
748
+ var args = arguments;
749
+ var now = Util.now();
750
+
751
+ if (!recent || (now - recent > delay)) {
752
+ func.apply(context, args);
753
+ recent = now;
754
+ }
755
+ };
756
+ },
740
757
 
741
- /**
742
- * Measures the number of milliseconds taken to run the provided callback
743
- * function. Uses a high-precision timer if available.
744
- */
745
- time: function time(cb) {
746
- var start = Util.now();
747
- cb();
748
- return Util.now() - start;
749
- },
758
+ /**
759
+ * Measures the number of milliseconds taken to run the provided callback
760
+ * function. Uses a high-precision timer if available.
761
+ */
762
+ time: function time(cb) {
763
+ var start = Util.now();
764
+ cb();
765
+ return Util.now() - start;
766
+ },
750
767
 
751
- /**
752
- * Get a unique ID.
753
- *
754
- * @returns {string} an unique numeric string
755
- */
756
- nextUid: function() {
757
- return '' + nextUniqueId++;
758
- },
768
+ /**
769
+ * Get a unique ID.
770
+ *
771
+ * @returns {string} an unique numeric string
772
+ */
773
+ nextUid: function () {
774
+ return '' + nextUniqueId++;
775
+ },
759
776
 
760
- // Stop watchers and events from firing on a scope without destroying it,
761
- // by disconnecting it from its parent and its siblings' linked lists.
762
- disconnectScope: function disconnectScope(scope) {
763
- if (!scope) return;
777
+ // Stop watchers and events from firing on a scope without destroying it,
778
+ // by disconnecting it from its parent and its siblings' linked lists.
779
+ disconnectScope: function disconnectScope(scope) {
780
+ if (!scope) return;
764
781
 
765
- // we can't destroy the root scope or a scope that has been already destroyed
766
- if (scope.$root === scope) return;
767
- if (scope.$$destroyed ) return;
782
+ // we can't destroy the root scope or a scope that has been already destroyed
783
+ if (scope.$root === scope) return;
784
+ if (scope.$$destroyed) return;
768
785
 
769
- var parent = scope.$parent;
770
- scope.$$disconnected = true;
786
+ var parent = scope.$parent;
787
+ scope.$$disconnected = true;
771
788
 
772
- // See Scope.$destroy
773
- if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling;
774
- if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling;
775
- if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling;
776
- if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling;
789
+ // See Scope.$destroy
790
+ if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling;
791
+ if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling;
792
+ if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling;
793
+ if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling;
777
794
 
778
- scope.$$nextSibling = scope.$$prevSibling = null;
795
+ scope.$$nextSibling = scope.$$prevSibling = null;
779
796
 
780
- },
797
+ },
781
798
 
782
- // Undo the effects of disconnectScope above.
783
- reconnectScope: function reconnectScope(scope) {
784
- if (!scope) return;
799
+ // Undo the effects of disconnectScope above.
800
+ reconnectScope: function reconnectScope(scope) {
801
+ if (!scope) return;
785
802
 
786
- // we can't disconnect the root node or scope already disconnected
787
- if (scope.$root === scope) return;
788
- if (!scope.$$disconnected) return;
803
+ // we can't disconnect the root node or scope already disconnected
804
+ if (scope.$root === scope) return;
805
+ if (!scope.$$disconnected) return;
789
806
 
790
- var child = scope;
807
+ var child = scope;
791
808
 
792
- var parent = child.$parent;
793
- child.$$disconnected = false;
794
- // See Scope.$new for this logic...
795
- child.$$prevSibling = parent.$$childTail;
796
- if (parent.$$childHead) {
797
- parent.$$childTail.$$nextSibling = child;
798
- parent.$$childTail = child;
799
- } else {
800
- parent.$$childHead = parent.$$childTail = child;
801
- }
802
- },
809
+ var parent = child.$parent;
810
+ child.$$disconnected = false;
811
+ // See Scope.$new for this logic...
812
+ child.$$prevSibling = parent.$$childTail;
813
+ if (parent.$$childHead) {
814
+ parent.$$childTail.$$nextSibling = child;
815
+ parent.$$childTail = child;
816
+ } else {
817
+ parent.$$childHead = parent.$$childTail = child;
818
+ }
819
+ },
803
820
 
804
- /*
805
- * getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching nodeName
806
- *
807
- * @param el Element to start walking the DOM from
808
- * @param tagName Tag name to find closest to el, such as 'form'
809
- */
810
- getClosest: function getClosest(el, tagName, onlyParent) {
811
- if (el instanceof angular.element) el = el[0];
812
- tagName = tagName.toUpperCase();
813
- if (onlyParent) el = el.parentNode;
814
- if (!el) return null;
815
- do {
816
- if (el.nodeName === tagName) {
817
- return el;
818
- }
819
- } while (el = el.parentNode);
820
- return null;
821
- },
821
+ /*
822
+ * getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching nodeName
823
+ *
824
+ * @param el Element to start walking the DOM from
825
+ * @param tagName Tag name to find closest to el, such as 'form'
826
+ */
827
+ getClosest: function getClosest(el, tagName, onlyParent) {
828
+ if (el instanceof angular.element) el = el[0];
829
+ tagName = tagName.toUpperCase();
830
+ if (onlyParent) el = el.parentNode;
831
+ if (!el) return null;
832
+ do {
833
+ if (el.nodeName === tagName) {
834
+ return el;
835
+ }
836
+ } while (el = el.parentNode);
837
+ return null;
838
+ },
822
839
 
823
- /**
824
- * Functional equivalent for $element.filter(‘md-bottom-sheet’)
825
- * useful with interimElements where the element and its container are important...
826
- */
827
- extractElementByName: function (element, nodeName) {
828
- for (var i = 0, len = element.length; i < len; i++) {
829
- if (element[i].nodeName.toLowerCase() === nodeName){
830
- return angular.element(element[i]);
840
+ /**
841
+ * Functional equivalent for $element.filter(‘md-bottom-sheet’)
842
+ * useful with interimElements where the element and its container are important...
843
+ */
844
+ extractElementByName: function (element, nodeName) {
845
+ for (var i = 0, len = element.length; i < len; i++) {
846
+ if (element[i].nodeName.toLowerCase() === nodeName) {
847
+ return angular.element(element[i]);
848
+ }
831
849
  }
832
- }
833
- return element;
834
- },
835
-
836
- /**
837
- * Give optional properties with no value a boolean true by default
838
- */
839
- initOptionalProperties: function (scope, attr, defaults ) {
840
- defaults = defaults || { };
841
- angular.forEach(scope.$$isolateBindings, function (binding, key) {
842
- if (binding.optional && angular.isUndefined(scope[key])) {
843
- var hasKey = attr.hasOwnProperty(attr.$normalize(binding.attrName));
850
+ return element;
851
+ },
844
852
 
845
- scope[key] = angular.isDefined(defaults[key]) ? defaults[key] : hasKey;
846
- }
847
- });
848
- }
853
+ /**
854
+ * Give optional properties with no value a boolean true if attr provided or false otherwise
855
+ */
856
+ initOptionalProperties: function (scope, attr, defaults) {
857
+ defaults = defaults || {};
858
+ angular.forEach(scope.$$isolateBindings, function (binding, key) {
859
+ if (binding.optional && angular.isUndefined(scope[key])) {
860
+ var attrIsDefined = angular.isDefined(attr[binding.attrName]);
861
+ scope[key] = angular.isDefined(defaults[key]) ? defaults[key] : attrIsDefined;
862
+ }
863
+ });
864
+ }
849
865
 
850
- };
866
+ };
851
867
 
852
- }]);
868
+ }]);
853
869
 
854
870
  /*
855
871
  * Since removing jQuery from the demos, some code that uses `element.focus()` is broken.
@@ -859,18 +875,18 @@ angular.module('material.core')
859
875
  * TODO(ajoslin): This should be added in a better place later.
860
876
  */
861
877
 
862
- angular.element.prototype.focus = angular.element.prototype.focus || function() {
863
- if (this.length) {
864
- this[0].focus();
865
- }
866
- return this;
867
- };
868
- angular.element.prototype.blur = angular.element.prototype.blur || function() {
869
- if (this.length) {
870
- this[0].blur();
871
- }
872
- return this;
873
- };
878
+ angular.element.prototype.focus = angular.element.prototype.focus || function () {
879
+ if (this.length) {
880
+ this[0].focus();
881
+ }
882
+ return this;
883
+ };
884
+ angular.element.prototype.blur = angular.element.prototype.blur || function () {
885
+ if (this.length) {
886
+ this[0].blur();
887
+ }
888
+ return this;
889
+ };
874
890
 
875
891
  })();
876
892
  (function(){
@@ -1034,8 +1050,8 @@ function mdCompilerService($q, $http, $injector, $compile, $controller, $templat
1034
1050
  var template = options.template || '';
1035
1051
  var controller = options.controller;
1036
1052
  var controllerAs = options.controllerAs;
1037
- var resolve = options.resolve || {};
1038
- var locals = options.locals || {};
1053
+ var resolve = angular.copy(options.resolve || {});
1054
+ var locals = angular.copy(options.locals || {});
1039
1055
  var transformTemplate = options.transformTemplate || angular.identity;
1040
1056
  var bindToController = options.bindToController;
1041
1057
 
@@ -2002,7 +2018,7 @@ function InterimElementProvider() {
2002
2018
  */
2003
2019
  function hide(response) {
2004
2020
  var interimElement = stack.shift();
2005
- return interimElement && interimElement.remove().then(function() {
2021
+ return $q.when(interimElement && interimElement.remove()).then(function() {
2006
2022
  interimElement.deferred.resolve(response);
2007
2023
  });
2008
2024
  }
@@ -2021,9 +2037,9 @@ function InterimElementProvider() {
2021
2037
  */
2022
2038
  function cancel(reason) {
2023
2039
  var interimElement = stack.shift();
2024
- return $q.when(interimElement && interimElement.remove().then(function() {
2040
+ return $q.when(interimElement && interimElement.remove()).then(function() {
2025
2041
  interimElement.deferred.reject(reason);
2026
- }));
2042
+ });
2027
2043
  }
2028
2044
 
2029
2045
 
@@ -2099,17 +2115,18 @@ function InterimElementProvider() {
2099
2115
  var ret = options.onShow(options.scope, element, options);
2100
2116
  return $q.when(ret)
2101
2117
  .then(function(){
2102
- // Issue onComplete callback when the `show()` finishes
2118
+ // Trigger onComplete callback when the `show()` finishes
2103
2119
  (options.onComplete || angular.noop)(options.scope, element, options);
2104
2120
  startHideTimeout();
2105
2121
  });
2106
2122
 
2107
2123
  function startHideTimeout() {
2108
2124
  if (options.hideDelay) {
2109
- hideTimeout = $timeout(service.cancel, options.hideDelay) ;
2125
+ hideTimeout = $timeout(service.hide, options.hideDelay) ;
2110
2126
  }
2111
2127
  }
2112
- }, function(reason) { showDone = true; self.deferred.reject(reason); });
2128
+ },
2129
+ function(reason) { showDone = true; self.deferred.reject(reason); })
2113
2130
  },
2114
2131
  cancelTimeout: function() {
2115
2132
  if (hideTimeout) {
@@ -2121,6 +2138,10 @@ function InterimElementProvider() {
2121
2138
  self.cancelTimeout();
2122
2139
  return removeDone = $q.when(showDone).then(function() {
2123
2140
  var ret = element ? options.onRemove(options.scope, element, options) : true;
2141
+
2142
+ // Trigger onRemoving callback *before* the remove operation starts
2143
+ (options.onRemoving || angular.noop)(options.scope, element);
2144
+
2124
2145
  return $q.when(ret).then(function() {
2125
2146
  if (!options.preserveScope) options.scope.$destroy();
2126
2147
  removeDone = true;
@@ -3541,6 +3562,9 @@ function ThemingProvider($mdColorPalette) {
3541
3562
  if (oldTheme) el.removeClass('md-' + oldTheme +'-theme');
3542
3563
  el.addClass('md-' + theme + '-theme');
3543
3564
  el.data('$mdThemeName', theme);
3565
+ if (ctrl) {
3566
+ el.data('$mdThemeController', ctrl);
3567
+ }
3544
3568
  }
3545
3569
  };
3546
3570
 
@@ -4153,85 +4177,6 @@ MdBottomSheetProvider.$inject = ["$$interimElementProvider"];
4153
4177
  (function(){
4154
4178
  "use strict";
4155
4179
 
4156
- /**
4157
- * @ngdoc module
4158
- * @name material.components.card
4159
- *
4160
- * @description
4161
- * Card components.
4162
- */
4163
- angular.module('material.components.card', [
4164
- 'material.core'
4165
- ])
4166
- .directive('mdCard', mdCardDirective);
4167
-
4168
-
4169
-
4170
- /**
4171
- * @ngdoc directive
4172
- * @name mdCard
4173
- * @module material.components.card
4174
- *
4175
- * @restrict E
4176
- *
4177
- * @description
4178
- * The `<md-card>` directive is a container element used within `<md-content>` containers.
4179
- *
4180
- * An image included as a direct descendant will fill the card's width, while the `<md-card-content>`
4181
- * container will wrap text content and provide padding. An `<md-card-footer>` element can be
4182
- * optionally included to put content flush against the bottom edge of the card.
4183
- *
4184
- * Action buttons can be included in an element with the `.md-actions` class, also used in `md-dialog`.
4185
- * You can then position buttons using layout attributes.
4186
- *
4187
- * Cards have constant width and variable heights; where the maximum height is limited to what can
4188
- * fit within a single view on a platform, but it can temporarily expand as needed.
4189
- *
4190
- * @usage
4191
- * ###Card with optional footer
4192
- * <hljs lang="html">
4193
- * <md-card>
4194
- * <img src="card-image.png" class="md-card-image" alt="image caption">
4195
- * <md-card-content>
4196
- * <h2>Card headline</h2>
4197
- * <p>Card content</p>
4198
- * </md-card-content>
4199
- * <md-card-footer>
4200
- * Card footer
4201
- * </md-card-footer>
4202
- * </md-card>
4203
- * </hljs>
4204
- *
4205
- * ###Card with actions
4206
- * <hljs lang="html">
4207
- * <md-card>
4208
- * <img src="card-image.png" class="md-card-image" alt="image caption">
4209
- * <md-card-content>
4210
- * <h2>Card headline</h2>
4211
- * <p>Card content</p>
4212
- * </md-card-content>
4213
- * <div class="md-actions" layout="row" layout-align="end center">
4214
- * <md-button>Action 1</md-button>
4215
- * <md-button>Action 2</md-button>
4216
- * </div>
4217
- * </md-card>
4218
- * </hljs>
4219
- *
4220
- */
4221
- function mdCardDirective($mdTheming) {
4222
- return {
4223
- restrict: 'E',
4224
- link: function($scope, $element, $attr) {
4225
- $mdTheming($element);
4226
- }
4227
- };
4228
- }
4229
- mdCardDirective.$inject = ["$mdTheming"];
4230
-
4231
- })();
4232
- (function(){
4233
- "use strict";
4234
-
4235
4180
  /**
4236
4181
  * @ngdoc module
4237
4182
  * @name material.components.button
@@ -4364,29 +4309,108 @@ MdButtonDirective.$inject = ["$mdButtonInkRipple", "$mdTheming", "$mdAria", "$ti
4364
4309
 
4365
4310
  /**
4366
4311
  * @ngdoc module
4367
- * @name material.components.checkbox
4368
- * @description Checkbox module!
4312
+ * @name material.components.card
4313
+ *
4314
+ * @description
4315
+ * Card components.
4369
4316
  */
4370
- angular
4371
- .module('material.components.checkbox', ['material.core'])
4372
- .directive('mdCheckbox', MdCheckboxDirective);
4317
+ angular.module('material.components.card', [
4318
+ 'material.core'
4319
+ ])
4320
+ .directive('mdCard', mdCardDirective);
4321
+
4322
+
4373
4323
 
4374
4324
  /**
4375
4325
  * @ngdoc directive
4376
- * @name mdCheckbox
4377
- * @module material.components.checkbox
4326
+ * @name mdCard
4327
+ * @module material.components.card
4328
+ *
4378
4329
  * @restrict E
4379
4330
  *
4380
4331
  * @description
4381
- * The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
4332
+ * The `<md-card>` directive is a container element used within `<md-content>` containers.
4382
4333
  *
4383
- * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
4384
- * the checkbox is in the accent color by default. The primary color palette may be used with
4385
- * the `md-primary` class.
4334
+ * An image included as a direct descendant will fill the card's width, while the `<md-card-content>`
4335
+ * container will wrap text content and provide padding. An `<md-card-footer>` element can be
4336
+ * optionally included to put content flush against the bottom edge of the card.
4386
4337
  *
4387
- * @param {string} ng-model Assignable angular expression to data-bind to.
4388
- * @param {string=} name Property name of the form under which the control is published.
4389
- * @param {expression=} ng-true-value The value to which the expression should be set when selected.
4338
+ * Action buttons can be included in an element with the `.md-actions` class, also used in `md-dialog`.
4339
+ * You can then position buttons using layout attributes.
4340
+ *
4341
+ * Cards have constant width and variable heights; where the maximum height is limited to what can
4342
+ * fit within a single view on a platform, but it can temporarily expand as needed.
4343
+ *
4344
+ * @usage
4345
+ * ###Card with optional footer
4346
+ * <hljs lang="html">
4347
+ * <md-card>
4348
+ * <img src="card-image.png" class="md-card-image" alt="image caption">
4349
+ * <md-card-content>
4350
+ * <h2>Card headline</h2>
4351
+ * <p>Card content</p>
4352
+ * </md-card-content>
4353
+ * <md-card-footer>
4354
+ * Card footer
4355
+ * </md-card-footer>
4356
+ * </md-card>
4357
+ * </hljs>
4358
+ *
4359
+ * ###Card with actions
4360
+ * <hljs lang="html">
4361
+ * <md-card>
4362
+ * <img src="card-image.png" class="md-card-image" alt="image caption">
4363
+ * <md-card-content>
4364
+ * <h2>Card headline</h2>
4365
+ * <p>Card content</p>
4366
+ * </md-card-content>
4367
+ * <div class="md-actions" layout="row" layout-align="end center">
4368
+ * <md-button>Action 1</md-button>
4369
+ * <md-button>Action 2</md-button>
4370
+ * </div>
4371
+ * </md-card>
4372
+ * </hljs>
4373
+ *
4374
+ */
4375
+ function mdCardDirective($mdTheming) {
4376
+ return {
4377
+ restrict: 'E',
4378
+ link: function($scope, $element, $attr) {
4379
+ $mdTheming($element);
4380
+ }
4381
+ };
4382
+ }
4383
+ mdCardDirective.$inject = ["$mdTheming"];
4384
+
4385
+ })();
4386
+ (function(){
4387
+ "use strict";
4388
+
4389
+ /**
4390
+ * @ngdoc module
4391
+ * @name material.components.checkbox
4392
+ * @description Checkbox module!
4393
+ */
4394
+ angular
4395
+ .module('material.components.checkbox', ['material.core'])
4396
+ .directive('mdCheckbox', MdCheckboxDirective);
4397
+
4398
+ /**
4399
+ * @ngdoc directive
4400
+ * @name mdCheckbox
4401
+ * @module material.components.checkbox
4402
+ * @restrict E
4403
+ *
4404
+ * @description
4405
+ * The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
4406
+ *
4407
+ * As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
4408
+ * the checkbox is in the accent color by default. The primary color palette may be used with
4409
+ * the `md-primary` class.
4410
+ *
4411
+ * @param {string} ng-model Assignable angular expression to data-bind to.
4412
+ * @param {string=} name Property name of the form under which the control is published.
4413
+ * @param {expression=} ng-true-value The value to which the expression should be set when selected.
4390
4414
  * @param {expression=} ng-false-value The value to which the expression should be set when not selected.
4391
4415
  * @param {string=} ng-change Angular expression to be executed when input changes due to user interaction with the input element.
4392
4416
  * @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects
@@ -4523,6 +4547,22 @@ MdCheckboxDirective.$inject = ["inputDirective", "$mdInkRipple", "$mdAria", "$md
4523
4547
  (function(){
4524
4548
  "use strict";
4525
4549
 
4550
+ /**
4551
+ * @ngdoc module
4552
+ * @name material.components.chips
4553
+ */
4554
+ /*
4555
+ * @see js folder for chips implementation
4556
+ */
4557
+ angular.module('material.components.chips', [
4558
+ 'material.core',
4559
+ 'material.components.autocomplete'
4560
+ ]);
4561
+
4562
+ })();
4563
+ (function(){
4564
+ "use strict";
4565
+
4526
4566
  /**
4527
4567
  * @ngdoc module
4528
4568
  * @name material.components.content
@@ -4602,22 +4642,6 @@ function iosScrollFix(node) {
4602
4642
  (function(){
4603
4643
  "use strict";
4604
4644
 
4605
- /**
4606
- * @ngdoc module
4607
- * @name material.components.chips
4608
- */
4609
- /*
4610
- * @see js folder for chips implementation
4611
- */
4612
- angular.module('material.components.chips', [
4613
- 'material.core',
4614
- 'material.components.autocomplete'
4615
- ]);
4616
-
4617
- })();
4618
- (function(){
4619
- "use strict";
4620
-
4621
4645
  /**
4622
4646
  * @ngdoc module
4623
4647
  * @name material.components.dialog
@@ -4632,9 +4656,9 @@ angular.module('material.components.dialog', [
4632
4656
  function MdDialogDirective($$rAF, $mdTheming) {
4633
4657
  return {
4634
4658
  restrict: 'E',
4635
- link: function(scope, element, attr) {
4659
+ link: function (scope, element, attr) {
4636
4660
  $mdTheming(element);
4637
- $$rAF(function() {
4661
+ $$rAF(function () {
4638
4662
  var content = element[0].querySelector('md-dialog-content');
4639
4663
  if (content && content.scrollHeight > content.clientHeight) {
4640
4664
  element.addClass('md-content-overflow');
@@ -4884,7 +4908,7 @@ MdDialogDirective.$inject = ["$$rAF", "$mdTheming"];
4884
4908
  * </hljs>
4885
4909
  */
4886
4910
 
4887
- /**
4911
+ /**
4888
4912
  * @ngdoc method
4889
4913
  * @name $mdDialog#alert
4890
4914
  *
@@ -4900,7 +4924,7 @@ MdDialogDirective.$inject = ["$$rAF", "$mdTheming"];
4900
4924
  *
4901
4925
  */
4902
4926
 
4903
- /**
4927
+ /**
4904
4928
  * @ngdoc method
4905
4929
  * @name $mdDialog#confirm
4906
4930
  *
@@ -4965,6 +4989,8 @@ MdDialogDirective.$inject = ["$$rAF", "$mdTheming"];
4965
4989
  * to the root element of the application.
4966
4990
  * - `onComplete` `{function=}`: Callback function used to announce when the show() action is
4967
4991
  * finished.
4992
+ * - `onRemoving` `{function=} Callback function used to announce the close/hide() action is
4993
+ * starting. This allows developers to run custom animations in parallel the close animations.
4968
4994
  *
4969
4995
  * @returns {promise} A promise that can be resolved with `$mdDialog.hide()` or
4970
4996
  * rejected with `$mdDialog.cancel()`.
@@ -4996,10 +5022,8 @@ MdDialogDirective.$inject = ["$$rAF", "$mdTheming"];
4996
5022
 
4997
5023
  function MdDialogProvider($$interimElementProvider) {
4998
5024
 
4999
- var alertDialogMethods = ['title', 'content', 'ariaLabel', 'ok'];
5000
-
5001
5025
  advancedDialogOptions.$inject = ["$mdDialog", "$mdTheming"];
5002
- dialogDefaultOptions.$inject = ["$mdAria", "$document", "$mdUtil", "$mdConstant", "$mdTheming", "$mdDialog", "$timeout", "$rootElement", "$animate", "$$rAF", "$q"];
5026
+ dialogDefaultOptions.$inject = ["$mdAria", "$document", "$mdUtil", "$mdConstant", "$mdTheming", "$mdDialog", "$timeout", "$rootElement", "$animate", "$$rAF"];
5003
5027
  return $$interimElementProvider('$mdDialog')
5004
5028
  .setDefaults({
5005
5029
  methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent', 'parent'],
@@ -5019,28 +5043,24 @@ function MdDialogProvider($$interimElementProvider) {
5019
5043
  return {
5020
5044
  template: [
5021
5045
  '<md-dialog md-theme="{{ dialog.theme }}" aria-label="{{ dialog.ariaLabel }}">',
5022
- '<md-dialog-content role="document" tabIndex="-1">',
5023
- '<h2 class="md-title">{{ dialog.title }}</h2>',
5024
- '<p>{{ dialog.content }}</p>',
5025
- '</md-dialog-content>',
5026
- '<div class="md-actions">',
5027
- '<md-button ng-if="dialog.$type == \'confirm\'"' +
5028
- ' ng-click="dialog.abort()" class="md-primary">',
5029
- '{{ dialog.cancel }}',
5030
- '</md-button>',
5031
- '<md-button ng-click="dialog.hide()" class="md-primary">',
5032
- '{{ dialog.ok }}',
5033
- '</md-button>',
5034
- '</div>',
5046
+ ' <md-dialog-content role="document" tabIndex="-1">',
5047
+ ' <h2 class="md-title">{{ dialog.title }}</h2>',
5048
+ ' <p>{{ dialog.content }}</p>',
5049
+ ' </md-dialog-content>',
5050
+ ' <div class="md-actions">',
5051
+ ' <md-button ng-if="dialog.$type == \'confirm\'"' +
5052
+ ' ng-click="dialog.abort()" class="md-primary">',
5053
+ ' {{ dialog.cancel }}',
5054
+ ' </md-button>',
5055
+ ' <md-button ng-click="dialog.hide()" class="md-primary">',
5056
+ ' {{ dialog.ok }}',
5057
+ ' </md-button>',
5058
+ ' </div>',
5035
5059
  '</md-dialog>'
5036
- ].join(''),
5060
+ ].join('').replace(/\s\s+/g,''),
5037
5061
  controller: function mdDialogCtrl() {
5038
- this.hide = function() {
5039
- $mdDialog.hide(true);
5040
- };
5041
- this.abort = function() {
5042
- $mdDialog.cancel();
5043
- };
5062
+ this.hide = function () { $mdDialog.hide(true); };
5063
+ this.abort = function (){ $mdDialog.cancel(); };
5044
5064
  },
5045
5065
  controllerAs: 'dialog',
5046
5066
  bindToController: true,
@@ -5049,7 +5069,7 @@ function MdDialogProvider($$interimElementProvider) {
5049
5069
  }
5050
5070
 
5051
5071
  /* @ngInject */
5052
- function dialogDefaultOptions($mdAria, $document, $mdUtil, $mdConstant, $mdTheming, $mdDialog, $timeout, $rootElement, $animate, $$rAF, $q) {
5072
+ function dialogDefaultOptions($mdAria, $document, $mdUtil, $mdConstant, $mdTheming, $mdDialog, $timeout, $rootElement, $animate, $$rAF) {
5053
5073
  return {
5054
5074
  hasBackdrop: true,
5055
5075
  isolateScope: true,
@@ -5060,156 +5080,206 @@ function MdDialogProvider($$interimElementProvider) {
5060
5080
  targetEvent: null,
5061
5081
  focusOnOpen: true,
5062
5082
  disableParentScroll: true,
5063
- transformTemplate: function(template) {
5083
+ transformTemplate: function (template) {
5064
5084
  return '<div class="md-dialog-container">' + template + '</div>';
5065
5085
  }
5066
5086
  };
5067
5087
 
5068
- function trapFocus(ev) {
5069
- var dialog = document.querySelector('md-dialog');
5070
-
5071
- if (dialog && !dialog.contains(ev.target)) {
5072
- ev.stopImmediatePropagation();
5073
- dialog.focus();
5074
- }
5075
- }
5076
-
5077
- // On show method for dialogs
5088
+ /**
5089
+ * Show method for dialogs
5090
+ */
5078
5091
  function onShow(scope, element, options) {
5079
- angular.element($document[0].body).addClass('md-dialog-is-showing');
5080
5092
  element = $mdUtil.extractElementByName(element, 'md-dialog');
5093
+ angular.element($document[0].body).addClass('md-dialog-is-showing');
5094
+
5095
+ captureSourceAndParent(element, options);
5096
+ configureAria(element.find('md-dialog'), options);
5097
+ showBackdrop(element, options);
5081
5098
 
5082
- // Incase the user provides a raw dom element, always wrap it in jqLite
5083
- options.parent = angular.element(options.parent);
5099
+ return dialogPopIn(element, options)
5100
+ .then(function () {
5101
+ activateListeners(element, options);
5102
+ lockScreenReader(element, options);
5103
+ focusOnOpen();
5104
+ });
5084
5105
 
5085
- options.popInTarget = angular.element((options.targetEvent || {}).target);
5086
- var closeButton = findCloseButton();
5106
+ function focusOnOpen() {
5107
+ if (options.focusOnOpen) {
5108
+ var target = (options.$type === 'alert') ? element.find('md-dialog-content') : findCloseButton();
5109
+ target.focus();
5110
+ }
5087
5111
 
5088
- if (options.hasBackdrop) {
5089
- // Fix for IE 10
5090
- var computeFrom = (options.parent[0] == $document[0].body && $document[0].documentElement
5091
- && $document[0].documentElement.scrollTop) ? angular.element($document[0].documentElement) : options.parent;
5092
- var parentOffset = computeFrom.prop('scrollTop');
5093
- options.backdrop = angular.element('<md-backdrop class="md-dialog-backdrop md-opaque">');
5094
- options.backdrop.css('top', parentOffset +'px');
5095
- $mdTheming.inherit(options.backdrop, options.parent);
5096
- $animate.enter(options.backdrop, options.parent);
5097
- element.css('top', parentOffset +'px');
5112
+ function findCloseButton() {
5113
+ //If no element with class dialog-close, try to find the last
5114
+ //button child in md-actions and assume it is a close button
5115
+ var closeButton = element[0].querySelector('.dialog-close');
5116
+ if (!closeButton) {
5117
+ var actionButtons = element[0].querySelectorAll('.md-actions button');
5118
+ closeButton = actionButtons[actionButtons.length - 1];
5119
+ }
5120
+ return angular.element(closeButton);
5121
+ }
5098
5122
  }
5099
5123
 
5100
- var role = 'dialog',
5101
- elementToFocus = closeButton;
5124
+ }
5102
5125
 
5103
- if (options.$type === 'alert') {
5104
- role = 'alertdialog';
5105
- elementToFocus = element.find('md-dialog-content');
5106
- }
5126
+ /**
5127
+ * Remove function for all dialogs
5128
+ */
5129
+ function onRemove(scope, element, options) {
5130
+ angular.element($document[0].body).removeClass('md-dialog-is-showing');
5107
5131
 
5108
- configureAria(element.find('md-dialog'), role, options);
5132
+ options.deactivateListeners();
5133
+ options.unlockScreenReader();
5134
+ options.hideBackdrop();
5109
5135
 
5110
- document.addEventListener('focus', trapFocus, true);
5136
+ return dialogPopOut(element, options)
5137
+ .then(function () {
5138
+ element.remove();
5139
+ options.origin.focus();
5140
+ });
5141
+ }
5111
5142
 
5112
- if (options.disableParentScroll) {
5113
- options.lastOverflow = options.parent.css('overflow');
5114
- options.parent.css('overflow', 'hidden');
5115
- }
5143
+ function captureSourceAndParent(element, options) {
5144
+ options.origin = {
5145
+ element: null,
5146
+ bounds: null,
5147
+ focus: angular.noop
5148
+ };
5149
+
5150
+ var source = angular.element((options.targetEvent || {}).target);
5151
+ if (source && source.length) {
5152
+ // Compute and save the target element's bounding rect, so that if the
5153
+ // element is hidden when the dialog closes, we can shrink the dialog
5154
+ // back to the same position it expanded from.
5155
+ options.origin.element = source;
5156
+ options.origin.bounds = source[0].getBoundingClientRect();
5157
+ options.origin.focus = function () {
5158
+ source.focus();
5159
+ }
5160
+ }
5116
5161
 
5117
- return dialogPopIn(
5118
- element,
5119
- options.parent,
5120
- options.popInTarget && options.popInTarget.length && options.popInTarget
5121
- )
5122
- .then(function() {
5162
+ // Incase the user provides a raw dom element, always wrap it in jqLite
5163
+ options.parent = angular.element(options.parent);
5123
5164
 
5124
- applyAriaToSiblings(element, true);
5165
+ if (options.disableParentScroll) {
5166
+ options.restoreScroll = $mdUtil.disableScrollAround(element);
5167
+ }
5168
+ }
5125
5169
 
5126
- if (options.escapeToClose) {
5127
- options.rootElementKeyupCallback = function(e) {
5128
- if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
5129
- $timeout($mdDialog.cancel);
5130
- }
5131
- };
5132
- $rootElement.on('keyup', options.rootElementKeyupCallback);
5133
- }
5170
+ /**
5171
+ * Listen for escape keys and outside clicks to auto close
5172
+ */
5173
+ function activateListeners(element, options) {
5174
+ var removeListeners = [ ];
5134
5175
 
5135
- if (options.clickOutsideToClose) {
5136
- options.dialogClickOutsideCallback = function(ev) {
5137
- // Only close if we click the flex container outside the backdrop
5138
- if (ev.target === element[0]) {
5139
- $timeout($mdDialog.cancel);
5140
- }
5141
- };
5142
- element.on('click', options.dialogClickOutsideCallback);
5143
- }
5176
+ if (options.escapeToClose) {
5177
+ var target = options.parent;
5178
+ var keyHandlerFn = function (ev) {
5179
+ if (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
5180
+ ev.stopPropagation();
5181
+ ev.preventDefault();
5144
5182
 
5145
- if (options.focusOnOpen) {
5146
- elementToFocus.focus();
5147
- }
5148
- });
5183
+ $timeout($mdDialog.cancel);
5184
+ }
5185
+ };
5149
5186
 
5187
+ // Add keyup listeners
5188
+ element.on('keyup', keyHandlerFn);
5189
+ target.on('keyup', keyHandlerFn);
5150
5190
 
5151
- function findCloseButton() {
5152
- //If no element with class dialog-close, try to find the last
5153
- //button child in md-actions and assume it is a close button
5154
- var closeButton = element[0].querySelector('.dialog-close');
5155
- if (!closeButton) {
5156
- var actionButtons = element[0].querySelectorAll('.md-actions button');
5157
- closeButton = actionButtons[ actionButtons.length - 1 ];
5158
- }
5159
- return angular.element(closeButton);
5191
+ // Queue remove listeners function
5192
+ removeListeners.push(function() {
5193
+ element.off('keyup', keyHandlerFn);
5194
+ target.off('keyup', keyHandlerFn);
5195
+ });
5160
5196
  }
5197
+ if (options.clickOutsideToClose) {
5198
+ var target = element;
5199
+ var clickHandler = function (ev) {
5200
+ // Only close if we click the flex container outside the backdrop
5201
+ if (ev.target === target[0]) {
5202
+ ev.stopPropagation();
5203
+ ev.preventDefault();
5161
5204
 
5162
- }
5205
+ $timeout($mdDialog.cancel);
5206
+ }
5207
+ };
5163
5208
 
5164
- // On remove function for all dialogs
5165
- function onRemove(scope, element, options) {
5166
- angular.element($document[0].body).removeClass('md-dialog-is-showing');
5209
+ // Add click listeners
5210
+ target.on('click', clickHandler);
5167
5211
 
5168
- if (options.backdrop) {
5169
- $animate.leave(options.backdrop);
5170
- }
5171
- if (options.disableParentScroll) {
5172
- options.parent.css('overflow', options.lastOverflow);
5173
- delete options.lastOverflow;
5174
- }
5175
- if (options.escapeToClose) {
5176
- $rootElement.off('keyup', options.rootElementKeyupCallback);
5177
- }
5178
- if (options.clickOutsideToClose) {
5179
- element.off('click', options.dialogClickOutsideCallback);
5212
+ // Queue remove listeners function
5213
+ removeListeners.push(function(){
5214
+ target.off('click',clickHandler);
5215
+ });
5180
5216
  }
5181
5217
 
5182
- applyAriaToSiblings(element, false);
5218
+ // Attach specific `remove` listener handler
5219
+ options.deactivateListeners = function() {
5220
+ removeListeners.forEach(function(removeFn){
5221
+ removeFn();
5222
+ });
5223
+ options.deactivateListeners = null;
5224
+ };
5225
+ }
5183
5226
 
5184
- document.removeEventListener('focus', trapFocus, true);
5185
5227
 
5186
- return dialogPopOut(
5187
- element,
5188
- options.parent,
5189
- options.popInTarget && options.popInTarget.length && options.popInTarget
5190
- ).then(function() {
5191
- element.remove();
5192
- options.popInTarget && options.popInTarget.focus();
5193
- });
5228
+ /**
5229
+ * Show modal backdrop element...
5230
+ */
5231
+ function showBackdrop(element, options) {
5232
+
5233
+ if (options.hasBackdrop) {
5234
+ // Fix for IE 10
5235
+ var docElement = $document[0].documentElement;
5236
+ var hasScrollTop = (options.parent[0] == $document[0].body) && (docElement && docElement.scrollTop);
5237
+ var computeFrom = hasScrollTop ? angular.element(docElement) : options.parent;
5238
+ var parentOffset = computeFrom.prop('scrollTop');
5239
+
5240
+ options.backdrop = angular.element('<md-backdrop class="md-dialog-backdrop md-opaque">');
5241
+ options.backdrop.css('top', parentOffset + 'px');
5242
+ $mdTheming.inherit(options.backdrop, options.parent);
5243
+
5244
+ $animate.enter(options.backdrop, options.parent);
5245
+ element.css('top', parentOffset + 'px');
5246
+ }
5247
+
5248
+ /**
5249
+ * Hide modal backdrop element...
5250
+ */
5251
+ options.hideBackdrop = function hideBackdrop() {
5252
+ if (options.backdrop) {
5253
+ $animate.leave(options.backdrop);
5254
+ }
5255
+ if (options.disableParentScroll) {
5256
+ options.restoreScroll();
5257
+ }
5194
5258
 
5259
+ options.hideBackdrop = null;
5260
+ }
5195
5261
  }
5196
5262
 
5263
+
5264
+
5197
5265
  /**
5198
5266
  * Inject ARIA-specific attributes appropriate for Dialogs
5199
5267
  */
5200
- function configureAria(element, role, options) {
5268
+ function configureAria(element, options) {
5269
+
5270
+ var role = (options.$type === 'alert') ? 'alertdialog' : 'dialog';
5271
+ var dialogContent = element.find('md-dialog-content');
5272
+ var dialogId = element.attr('id') || ('dialog_' + $mdUtil.nextUid());
5201
5273
 
5202
5274
  element.attr({
5203
5275
  'role': role,
5204
5276
  'tabIndex': '-1'
5205
5277
  });
5206
5278
 
5207
- var dialogContent = element.find('md-dialog-content');
5208
- if (dialogContent.length === 0){
5279
+ if (dialogContent.length === 0) {
5209
5280
  dialogContent = element;
5210
5281
  }
5211
5282
 
5212
- var dialogId = element.attr('id') || ('dialog_' + $mdUtil.nextUid());
5213
5283
  dialogContent.attr('id', dialogId);
5214
5284
  element.attr('aria-describedby', dialogId);
5215
5285
 
@@ -5217,34 +5287,36 @@ function MdDialogProvider($$interimElementProvider) {
5217
5287
  $mdAria.expect(element, 'aria-label', options.ariaLabel);
5218
5288
  }
5219
5289
  else {
5220
- $mdAria.expectAsync(element, 'aria-label', function() {
5290
+ $mdAria.expectAsync(element, 'aria-label', function () {
5221
5291
  var words = dialogContent.text().split(/\s+/);
5222
- if (words.length > 3) words = words.slice(0,3).concat('...');
5292
+ if (words.length > 3) words = words.slice(0, 3).concat('...');
5223
5293
  return words.join(' ');
5224
5294
  });
5225
5295
  }
5226
5296
  }
5297
+
5227
5298
  /**
5228
- * Utility function to filter out raw DOM nodes
5229
- */
5230
- function isNodeOneOf(elem, nodeTypeArray) {
5231
- if (nodeTypeArray.indexOf(elem.nodeName) !== -1) {
5232
- return true;
5233
- }
5234
- }
5235
- /**
5236
- * Walk DOM to apply or remove aria-hidden on sibling nodes
5237
- * and parent sibling nodes
5238
- *
5239
5299
  * Prevents screen reader interaction behind modal window
5240
5300
  * on swipe interfaces
5241
5301
  */
5242
- function applyAriaToSiblings(element, value) {
5243
- var attribute = 'aria-hidden';
5302
+ function lockScreenReader(element, options) {
5303
+ var isHidden = true;
5244
5304
 
5245
5305
  // get raw DOM node
5246
- element = element[0];
5306
+ walkDOM(element[0]);
5247
5307
 
5308
+ options.unlockScreenReader = function() {
5309
+ isHidden = false;
5310
+ walkDOM(element[0]);
5311
+
5312
+ options.unlockScreenReader = null;
5313
+ };
5314
+
5315
+ /**
5316
+ * Walk DOM to apply or remove aria-hidden on sibling nodes
5317
+ * and parent sibling nodes
5318
+ *
5319
+ */
5248
5320
  function walkDOM(element) {
5249
5321
  while (element.parentNode) {
5250
5322
  if (element === document.body) {
@@ -5255,68 +5327,82 @@ function MdDialogProvider($$interimElementProvider) {
5255
5327
  // skip over child if it is an ascendant of the dialog
5256
5328
  // or a script or style tag
5257
5329
  if (element !== children[i] && !isNodeOneOf(children[i], ['SCRIPT', 'STYLE'])) {
5258
- children[i].setAttribute(attribute, value);
5330
+ children[i].setAttribute('aria-hidden', isHidden);
5259
5331
  }
5260
5332
  }
5261
5333
 
5262
5334
  walkDOM(element = element.parentNode);
5263
5335
  }
5264
5336
  }
5265
- walkDOM(element);
5266
5337
  }
5267
5338
 
5268
- function dialogPopIn(container, parentElement, clickElement) {
5339
+ /**
5340
+ * Dialog open and pop-in animation
5341
+ */
5342
+ function dialogPopIn(container, options ) {
5269
5343
  var dialogEl = container.find('md-dialog');
5270
5344
 
5271
- parentElement.append(container);
5272
- transformToClickElement(dialogEl, clickElement);
5345
+ options.parent.append(container);
5346
+ transformToClickElement(dialogEl, options.origin);
5273
5347
 
5274
- $$rAF(function() {
5275
- dialogEl.addClass('transition-in')
5348
+ $$rAF(function () {
5349
+ dialogEl.addClass('md-transition-in')
5276
5350
  .css($mdConstant.CSS.TRANSFORM, '');
5277
5351
  });
5278
5352
 
5279
5353
  return $mdUtil.transitionEndPromise(dialogEl);
5280
5354
  }
5281
5355
 
5282
- function dialogPopOut(container, parentElement, clickElement) {
5356
+ /**
5357
+ * Dialog close and pop-out animation
5358
+ */
5359
+ function dialogPopOut(container, options) {
5283
5360
  var dialogEl = container.find('md-dialog');
5284
5361
 
5285
- dialogEl.addClass('transition-out').removeClass('transition-in');
5286
- transformToClickElement(dialogEl, clickElement);
5362
+ dialogEl.addClass('md-transition-out').removeClass('md-transition-in');
5363
+ transformToClickElement(dialogEl, options.origin);
5287
5364
 
5288
5365
  return $mdUtil.transitionEndPromise(dialogEl);
5289
5366
  }
5290
5367
 
5291
- function transformToClickElement(dialogEl, clickElement) {
5292
- if (clickElement) {
5293
- var clickRect = clickElement[0].getBoundingClientRect();
5294
- var dialogRect = dialogEl[0].getBoundingClientRect();
5368
+ /**
5369
+ * Utility function to filter out raw DOM nodes
5370
+ */
5371
+ function isNodeOneOf(elem, nodeTypeArray) {
5372
+ if (nodeTypeArray.indexOf(elem.nodeName) !== -1) {
5373
+ return true;
5374
+ }
5375
+ }
5295
5376
 
5296
- var scaleX = Math.min(0.5, clickRect.width / dialogRect.width);
5297
- var scaleY = Math.min(0.5, clickRect.height / dialogRect.height);
5377
+
5378
+ function isPositiveSizeClientRect(rect) {
5379
+ return rect && (rect.width > 0) && (rect.height > 0);
5380
+ }
5381
+
5382
+ function transformToClickElement(dialogEl, originator) {
5383
+ var target = originator.element;
5384
+ var targetBnds = originator.bounds;
5385
+
5386
+ if (target) {
5387
+ var currentBnds = target[0].getBoundingClientRect();
5388
+ // If the event target element has zero size, it has probably been hidden.
5389
+ // Use its initial position if available.
5390
+ if (isPositiveSizeClientRect(currentBnds)) {
5391
+ targetBnds = currentBnds;
5392
+ }
5393
+
5394
+ var dialogRect = dialogEl[0].getBoundingClientRect();
5395
+ var scaleX = Math.min(0.5, targetBnds.width / dialogRect.width);
5396
+ var scaleY = Math.min(0.5, targetBnds.height / dialogRect.height);
5298
5397
 
5299
5398
  dialogEl.css($mdConstant.CSS.TRANSFORM, 'translate3d(' +
5300
- (-dialogRect.left + clickRect.left + clickRect.width/2 - dialogRect.width/2) + 'px,' +
5301
- (-dialogRect.top + clickRect.top + clickRect.height/2 - dialogRect.height/2) + 'px,' +
5399
+ (-dialogRect.left + targetBnds.left + targetBnds.width / 2 - dialogRect.width / 2) + 'px,' +
5400
+ (-dialogRect.top + targetBnds.top + targetBnds.height / 2 - dialogRect.height / 2) + 'px,' +
5302
5401
  '0) scale(' + scaleX + ',' + scaleY + ')'
5303
5402
  );
5304
5403
  }
5305
5404
  }
5306
5405
 
5307
- function dialogTransitionEnd(dialogEl) {
5308
- var deferred = $q.defer();
5309
- dialogEl.on($mdConstant.CSS.TRANSITIONEND, finished);
5310
- function finished(ev) {
5311
- //Make sure this transitionend didn't bubble up from a child
5312
- if (ev.target === dialogEl[0]) {
5313
- dialogEl.off($mdConstant.CSS.TRANSITIONEND, finished);
5314
- deferred.resolve();
5315
- }
5316
- }
5317
- return deferred.promise;
5318
- }
5319
-
5320
5406
  }
5321
5407
  }
5322
5408
  MdDialogProvider.$inject = ["$$interimElementProvider"];
@@ -5393,26 +5479,38 @@ MdDividerDirective.$inject = ["$mdTheming"];
5393
5479
 
5394
5480
  require: ['^?mdFabSpeedDial', '^?mdFabToolbar'],
5395
5481
 
5396
- link: function(scope, element, attributes, controllers) {
5397
- // Grab whichever parent controller is used
5398
- var controller = controllers[0] || controllers[1];
5482
+ compile: function(element, attributes) {
5483
+ var children = element.children();
5399
5484
 
5400
- // Make the children open/close their parent directive
5401
- if (controller) {
5402
- angular.forEach(element.children(), function(child) {
5403
- angular.element(child).on('focus', controller.open);
5404
- angular.element(child).on('blur', controller.close);
5405
- });
5485
+ // Support both ng-repat and static content
5486
+ if (children.attr('ng-repeat')) {
5487
+ children.addClass('md-fab-action-item');
5488
+ } else {
5489
+ // Wrap every child in a new div and add a class that we can scale/fling independently
5490
+ children.wrap('<div class="md-fab-action-item">');
5406
5491
  }
5407
5492
 
5408
- // After setting up the listeners, wrap every child in a new div and add a class that we can
5409
- // scale/fling independently
5410
- element.children().wrap('<div class="md-fab-action-item">');
5493
+ return function postLink(scope, element, attributes, controllers) {
5494
+ // Grab whichever parent controller is used
5495
+ var controller = controllers[0] || controllers[1];
5496
+
5497
+ // Make the children open/close their parent directive
5498
+ if (controller) {
5499
+ angular.forEach(element.children(), function(child) {
5500
+ // Attach listeners to the `md-fab-action-item`
5501
+ child = angular.element(child).children()[0];
5502
+
5503
+ angular.element(child).on('focus', controller.open);
5504
+ angular.element(child).on('blur', controller.close);
5505
+ });
5506
+ }
5507
+ }
5411
5508
  }
5412
5509
  }
5413
5510
  }
5414
5511
 
5415
5512
  })();
5513
+
5416
5514
  })();
5417
5515
  (function(){
5418
5516
  "use strict";
@@ -5421,14 +5519,23 @@ MdDividerDirective.$inject = ["$mdTheming"];
5421
5519
  'use strict';
5422
5520
 
5423
5521
  angular
5522
+ // Declare our module
5424
5523
  .module('material.components.fabSpeedDial', [
5425
5524
  'material.core',
5426
5525
  'material.components.fabTrigger',
5427
5526
  'material.components.fabActions'
5428
5527
  ])
5528
+
5529
+ // Register our directive
5429
5530
  .directive('mdFabSpeedDial', MdFabSpeedDialDirective)
5531
+
5532
+ // Register our custom animations
5430
5533
  .animation('.md-fling', MdFabSpeedDialFlingAnimation)
5431
- .animation('.md-scale', MdFabSpeedDialScaleAnimation);
5534
+ .animation('.md-scale', MdFabSpeedDialScaleAnimation)
5535
+
5536
+ // Register a service for each animation so that we can easily inject them into unit tests
5537
+ .service('mdFabSpeedDialFlingAnimation', MdFabSpeedDialFlingAnimation)
5538
+ .service('mdFabSpeedDialScaleAnimation', MdFabSpeedDialScaleAnimation);
5432
5539
 
5433
5540
  /**
5434
5541
  * @ngdoc directive
@@ -5472,7 +5579,7 @@ MdDividerDirective.$inject = ["$mdTheming"];
5472
5579
  * @param {expression=} md-open Programmatically control whether or not the speed-dial is visible.
5473
5580
  */
5474
5581
  function MdFabSpeedDialDirective() {
5475
- FabSpeedDialController.$inject = ["$scope", "$element", "$animate"];
5582
+ FabSpeedDialController.$inject = ["$scope", "$element", "$animate", "$timeout"];
5476
5583
  return {
5477
5584
  restrict: 'E',
5478
5585
 
@@ -5493,23 +5600,41 @@ MdDividerDirective.$inject = ["$mdTheming"];
5493
5600
  element.prepend('<div class="md-css-variables"></div>');
5494
5601
  }
5495
5602
 
5496
- function FabSpeedDialController($scope, $element, $animate) {
5603
+ function FabSpeedDialController($scope, $element, $animate, $timeout) {
5497
5604
  var vm = this;
5498
5605
 
5499
5606
  // Define our open/close functions
5500
5607
  // Note: Used by fabTrigger and fabActions directives
5501
5608
  vm.open = function() {
5502
- $scope.$apply('vm.isOpen = true');
5609
+ // Async eval to avoid conflicts with existing digest loops
5610
+ $scope.$evalAsync("vm.isOpen = true");
5503
5611
  };
5504
5612
 
5505
5613
  vm.close = function() {
5506
- $scope.$apply('vm.isOpen = false');
5614
+ // Async eval to avoid conflicts with existing digest loops
5615
+ // Only close if we do not currently have mouse focus (since child elements can call this)
5616
+ !vm.moused && $scope.$evalAsync("vm.isOpen = false");
5617
+ };
5618
+
5619
+ vm.mouseenter = function() {
5620
+ vm.moused = true;
5621
+ vm.open();
5622
+ };
5623
+
5624
+ vm.mouseleave = function() {
5625
+ vm.moused = false;
5626
+ vm.close();
5507
5627
  };
5508
5628
 
5509
5629
  setupDefaults();
5510
5630
  setupListeners();
5511
5631
  setupWatchers();
5512
5632
 
5633
+ // Fire the animations once in a separate digest loop to initialize them
5634
+ $timeout(function() {
5635
+ $animate.addClass($element, 'md-noop');
5636
+ }, 0);
5637
+
5513
5638
  // Set our default variables
5514
5639
  function setupDefaults() {
5515
5640
  // Set the default direction to 'down' if none is specified
@@ -5521,8 +5646,8 @@ MdDividerDirective.$inject = ["$mdTheming"];
5521
5646
 
5522
5647
  // Setup our event listeners
5523
5648
  function setupListeners() {
5524
- $element.on('mouseenter', vm.open);
5525
- $element.on('mouseleave', vm.close);
5649
+ $element.on('mouseenter', vm.mouseenter);
5650
+ $element.on('mouseleave', vm.mouseleave);
5526
5651
  }
5527
5652
 
5528
5653
  // Setup our watchers
@@ -5562,18 +5687,19 @@ MdDividerDirective.$inject = ["$mdTheming"];
5562
5687
  angular.forEach(items, function(item, index) {
5563
5688
  var styles = item.style;
5564
5689
 
5565
- styles.transform = '';
5690
+ styles.transform = styles.webkitTransform = '';
5566
5691
  styles.transitionDelay = '';
5567
5692
  styles.opacity = 1;
5568
5693
 
5569
5694
  // Make the items closest to the trigger have the highest z-index
5570
- item.style.zIndex = (items.length - index) + startZIndex;
5695
+ styles.zIndex = (items.length - index) + startZIndex;
5571
5696
  });
5572
5697
 
5573
5698
  // If the control is closed, hide the items behind the trigger
5574
5699
  if (!ctrl.isOpen) {
5575
5700
  angular.forEach(items, function(item, index) {
5576
5701
  var newPosition, axis;
5702
+ var styles = item.style;
5577
5703
 
5578
5704
  switch (ctrl.direction) {
5579
5705
  case 'up':
@@ -5594,7 +5720,9 @@ MdDividerDirective.$inject = ["$mdTheming"];
5594
5720
  break;
5595
5721
  }
5596
5722
 
5597
- item.style.transform = 'translate' + axis + '(' + newPosition + 'px)';
5723
+ var newTranslate = 'translate' + axis + '(' + newPosition + 'px)';
5724
+
5725
+ styles.transform = styles.webkitTransform = newTranslate;
5598
5726
  });
5599
5727
  }
5600
5728
  }
@@ -5603,10 +5731,12 @@ MdDividerDirective.$inject = ["$mdTheming"];
5603
5731
  addClass: function(element, className, done) {
5604
5732
  if (element.hasClass('md-fling')) {
5605
5733
  runAnimation(element);
5734
+ done();
5606
5735
  }
5607
5736
  },
5608
5737
  removeClass: function(element, className, done) {
5609
5738
  runAnimation(element);
5739
+ done();
5610
5740
  }
5611
5741
  }
5612
5742
  }
@@ -5625,7 +5755,7 @@ MdDividerDirective.$inject = ["$mdTheming"];
5625
5755
  offsetDelay = index * delay;
5626
5756
 
5627
5757
  styles.opacity = ctrl.isOpen ? 1 : 0;
5628
- styles.transform = ctrl.isOpen ? 'scale(1)' : 'scale(0)';
5758
+ styles.transform = styles.webkitTransform = ctrl.isOpen ? 'scale(1)' : 'scale(0)';
5629
5759
  styles.transitionDelay = (ctrl.isOpen ? offsetDelay : (items.length - offsetDelay)) + 'ms';
5630
5760
  });
5631
5761
  }
@@ -5633,10 +5763,12 @@ MdDividerDirective.$inject = ["$mdTheming"];
5633
5763
  return {
5634
5764
  addClass: function(element, className, done) {
5635
5765
  runAnimation(element);
5766
+ done();
5636
5767
  },
5637
5768
 
5638
5769
  removeClass: function(element, className, done) {
5639
5770
  runAnimation(element);
5771
+ done();
5640
5772
  }
5641
5773
  }
5642
5774
  }
@@ -5650,13 +5782,21 @@ MdDividerDirective.$inject = ["$mdTheming"];
5650
5782
  'use strict';
5651
5783
 
5652
5784
  angular
5785
+ // Declare our module
5653
5786
  .module('material.components.fabToolbar', [
5654
5787
  'material.core',
5655
5788
  'material.components.fabTrigger',
5656
5789
  'material.components.fabActions'
5657
5790
  ])
5791
+
5792
+ // Register our directive
5658
5793
  .directive('mdFabToolbar', MdFabToolbarDirective)
5659
- .animation('.md-fab-toolbar', MdFabToolbarAnimation);
5794
+
5795
+ // Register our custom animations
5796
+ .animation('.md-fab-toolbar', MdFabToolbarAnimation)
5797
+
5798
+ // Register a service for the animation so that we can easily inject it into unit tests
5799
+ .service('mdFabToolbarAnimation', MdFabToolbarAnimation);
5660
5800
 
5661
5801
  /**
5662
5802
  * @ngdoc directive
@@ -5806,7 +5946,7 @@ MdDividerDirective.$inject = ["$mdTheming"];
5806
5946
 
5807
5947
  // Set the next close animation to have the proper delays
5808
5948
  backgroundElement.style.transitionDelay = '0ms';
5809
- iconElement.style.transitionDelay = '.3s';
5949
+ iconElement && (iconElement.style.transitionDelay = '.3s');
5810
5950
 
5811
5951
  // Apply a transition delay to actions
5812
5952
  angular.forEach(actions, function(action, index) {
@@ -5832,7 +5972,7 @@ MdDividerDirective.$inject = ["$mdTheming"];
5832
5972
 
5833
5973
  // Set the next open animation to have the proper delays
5834
5974
  backgroundElement.style.transitionDelay = '200ms';
5835
- iconElement.style.transitionDelay = '0ms';
5975
+ iconElement && (iconElement.style.transitionDelay = '0ms');
5836
5976
 
5837
5977
  // Apply a transition delay to actions
5838
5978
  angular.forEach(actions, function(action, index) {
@@ -5845,10 +5985,12 @@ MdDividerDirective.$inject = ["$mdTheming"];
5845
5985
  return {
5846
5986
  addClass: function(element, className, done) {
5847
5987
  runAnimation(element, className, done);
5988
+ done();
5848
5989
  },
5849
5990
 
5850
5991
  removeClass: function(element, className, done) {
5851
5992
  runAnimation(element, className, done);
5993
+ done();
5852
5994
  }
5853
5995
  }
5854
5996
  }
@@ -6682,10 +6824,35 @@ angular.module('material.components.icon', [
6682
6824
  * @restrict E
6683
6825
  *
6684
6826
  * @description
6685
- * The `<md-icon>` directive is an markup element useful for showing an icon based on a font-icon
6686
- * or a SVG. Icons are view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`
6827
+ * The `md-icon` directive makes it easier to use vector-based icons in your app (as opposed to
6828
+ * raster-based icons types like PNG). The directive supports both icon fonts and SVG icons.
6829
+ *
6830
+ * Icons should be consider view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`
6687
6831
  * inside a `md-button` to add hover and click features.
6688
6832
  *
6833
+ * ### Icon fonts
6834
+ * Icon fonts are a technique in which you use a font where the glyphs in the font are
6835
+ * your icons instead of text. Benefits include a straightforward way to bundle everything into a
6836
+ * single HTTP request, simple scaling, easy color changing, and more.
6837
+ *
6838
+ * `md-icon` let's you consume an icon font by letting you reference specific icons in that font
6839
+ * by name rather than character code.
6840
+ *
6841
+ * ### SVG
6842
+ * For SVGs, the problem with using `<img>` or a CSS `background-image` is that you can't take
6843
+ * advantage of some SVG features, such as styling specific parts of the icon with CSS or SVG
6844
+ * animation.
6845
+ *
6846
+ * `md-icon` makes it easier to use SVG icons by *inlining* the SVG into an `<svg>` element in the
6847
+ * document. The most straightforward way of referencing an SVG icon is via URL, just like a
6848
+ * traditional `<img>`. `$mdIconProvider`, as a convenience, let's you _name_ an icon so you can
6849
+ * reference it by name instead of URL throughout your templates.
6850
+ *
6851
+ * Additionally, you may not want to make separate HTTP requests for every icon, so you can bundle
6852
+ * your SVG icons together and pre-load them with $mdIconProvider as an icon set. An icon set can
6853
+ * also be given a name, which acts as a namespace for individual icons, so you can reference them
6854
+ * like `"social:cake"`.
6855
+ *
6689
6856
  * When using SVGs, both external SVGs (via URLs) or sets of SVGs [from icon sets] can be
6690
6857
  * easily loaded and used.When use font-icons, developers must following three (3) simple steps:
6691
6858
  *
@@ -6731,19 +6898,23 @@ angular.module('material.components.icon', [
6731
6898
  * <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank">Material Design Icon-Selector</a>.
6732
6899
  * </span>
6733
6900
  *
6734
- * @param {string} md-font-icon Name of CSS icon associated with the font-face will be used
6901
+ * @param {string} md-font-icon String name of CSS icon associated with the font-face will be used
6735
6902
  * to render the icon. Requires the fonts and the named CSS styles to be preloaded.
6736
6903
  * @param {string} md-font-set CSS style name associated with the font library; which will be assigned as
6737
6904
  * the class for the font-icon ligature. This value may also be an alias that is used to lookup the classname;
6738
6905
  * internally use `$mdIconProvider.fontSet(<alias>)` to determine the style name.
6739
- * @param {string} md-svg-src URL [or expression ] used to load, cache, and display an external SVG.
6740
- * @param {string} md-svg-icon Name used for lookup of the icon from the internal cache; interpolated strings or
6741
- * expressions may also be used. Specific set names can be used with the syntax `<set name>:<icon name>`.<br/><br/>
6906
+ * @param {string} md-svg-src String URL (or expression) used to load, cache, and display an
6907
+ * external SVG.
6908
+ * @param {string} md-svg-icon md-svg-icon String name used for lookup of the icon from the internal cache;
6909
+ * interpolated strings or expressions may also be used. Specific set names can be used with
6910
+ * the syntax `<set name>:<icon name>`.<br/><br/>
6742
6911
  * To use icon sets, developers are required to pre-register the sets using the `$mdIconProvider` service.
6743
6912
  * @param {string=} aria-label Labels icon for accessibility. If an empty string is provided, icon
6744
6913
  * will be hidden from accessibility layer with `aria-hidden="true"`. If there's no aria-label on the icon
6745
6914
  * nor a label on the parent element, a warning will be logged to the console.
6746
- *
6915
+ * @param {string=} alt Labels icon for accessibility. If an empty string is provided, icon
6916
+ * will be hidden from accessibility layer with `aria-hidden="true"`. If there's no alt on the icon
6917
+ * nor a label on the parent element, a warning will be logged to the console. *
6747
6918
  * @usage
6748
6919
  * When using SVGs:
6749
6920
  * <hljs lang="html">
@@ -6782,11 +6953,12 @@ angular.module('material.components.icon', [
6782
6953
  * When using Material Font Icons with ligatures:
6783
6954
  * <hljs lang="html">
6784
6955
  * <!-- For Material Design Icons -->
6785
- * <!-- The class '.material-icons' is auto-added. -->
6956
+ * <!-- The class '.material-icons' is auto-added if a style has NOT been specified -->
6786
6957
  * <md-icon> face </md-icon>
6787
- * <md-icon class="md-light md-48"> face </md-icon>
6788
6958
  * <md-icon md-font-set="material-icons"> face </md-icon>
6789
6959
  * <md-icon> #xE87C; </md-icon>
6960
+ * <!-- The class '.material-icons' must be manually added if other styles are also specified-->
6961
+ * <md-icon class="material-icons md-light md-48"> face </md-icon>
6790
6962
  * </hljs>
6791
6963
  *
6792
6964
  * When using other Font-Icon libraries:
@@ -6803,7 +6975,7 @@ angular.module('material.components.icon', [
6803
6975
  * </hljs>
6804
6976
  *
6805
6977
  */
6806
- function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
6978
+ function mdIconDirective($mdIcon, $mdTheming, $mdAria ) {
6807
6979
 
6808
6980
  return {
6809
6981
  scope: {
@@ -6874,18 +7046,29 @@ function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
6874
7046
 
6875
7047
  function prepareForFontIcon () {
6876
7048
  if (!scope.svgIcon && !scope.svgSrc) {
7049
+
6877
7050
  if (scope.fontIcon) {
6878
7051
  element.addClass('md-font');
6879
7052
  element.addClass(scope.fontIcon);
6880
- } else {
7053
+ }
7054
+
7055
+ if (scope.fontSet) {
6881
7056
  element.addClass($mdIcon.fontSet(scope.fontSet));
6882
7057
  }
7058
+
7059
+ // For Material Design font icons, the class '.material-icons'
7060
+ // is auto-added IF a style has not been specified
7061
+
7062
+ if (!scope.fontIcon && !scope.fontSet && !angular.isDefined(attr.class)) {
7063
+
7064
+ element.addClass('material-icons');
7065
+ }
6883
7066
  }
6884
7067
 
6885
7068
  }
6886
7069
  }
6887
7070
  }
6888
- mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria", "$interpolate"];
7071
+ mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria"];
6889
7072
 
6890
7073
  })();
6891
7074
  (function(){
@@ -7149,6 +7332,7 @@ mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria", "$interpolate"];
7149
7332
  alias : alias,
7150
7333
  fontSet : className || alias
7151
7334
  });
7335
+ return this;
7152
7336
  },
7153
7337
 
7154
7338
  /**
@@ -7187,7 +7371,7 @@ mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria", "$interpolate"];
7187
7371
  {
7188
7372
  id: 'md-menu',
7189
7373
  url: 'md-menu.svg',
7190
- svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 100 100"><path d="M 50 0 L 100 14 L 92 80 L 50 100 L 8 80 L 0 14 Z" fill="#b2b2b2"></path><path d="M 50 5 L 6 18 L 13.5 77 L 50 94 Z" fill="#E42939"></path><path d="M 50 5 L 94 18 L 86.5 77 L 50 94 Z" fill="#B72833"></path><path d="M 50 7 L 83 75 L 72 75 L 65 59 L 50 59 L 50 50 L 61 50 L 50 26 Z" fill="#b2b2b2"></path><path d="M 50 7 L 17 75 L 28 75 L 35 59 L 50 59 L 50 50 L 39 50 L 50 26 Z" fill="#fff"></path></svg>'
7374
+ svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><path d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" /></svg>'
7191
7375
  },
7192
7376
  {
7193
7377
  id: 'md-toggle-arrow',
@@ -7559,6 +7743,7 @@ function labelDirective() {
7559
7743
  * The purpose of **`md-maxlength`** is exactly to show the max length counter text. If you don't want the counter text and only need "plain" validation, you can use the "simple" `ng-maxlength` or maxlength attributes.
7560
7744
  * @param {string=} aria-label Aria-label is required when no label is present. A warning message will be logged in the console if not present.
7561
7745
  * @param {string=} placeholder An alternative approach to using aria-label when the label is not present. The placeholder text is copied to the aria-label attribute.
7746
+ * @param md-no-autogrow {boolean=} When present, textareas will not grow automatically.
7562
7747
  *
7563
7748
  * @usage
7564
7749
  * <hljs lang="html">
@@ -7617,7 +7802,7 @@ function inputTextareaDirective($mdUtil, $window, $mdAria) {
7617
7802
 
7618
7803
  if ( !containerCtrl ) return;
7619
7804
  if (containerCtrl.input) {
7620
- throw new Error("<md-input-container> can only have *one* <input> or <textarea> child element!");
7805
+ throw new Error("<md-input-container> can only have *one* <input>, <textarea> or <md-select> child element!");
7621
7806
  }
7622
7807
  containerCtrl.input = element;
7623
7808
 
@@ -7679,7 +7864,21 @@ function inputTextareaDirective($mdUtil, $window, $mdAria) {
7679
7864
  }
7680
7865
 
7681
7866
  function setupTextarea() {
7867
+ if(angular.isDefined(element.attr('md-no-autogrow'))) {
7868
+ return;
7869
+ }
7870
+
7682
7871
  var node = element[0];
7872
+ var container = containerCtrl.element[0];
7873
+
7874
+ var min_rows = NaN;
7875
+ var lineHeight = null;
7876
+ // can't check if height was or not explicity set,
7877
+ // so rows attribute will take precedence if present
7878
+ if(node.hasAttribute('rows')) {
7879
+ min_rows = parseInt(node.getAttribute('rows'));
7880
+ }
7881
+
7683
7882
  var onChangeTextarea = $mdUtil.debounce(growTextarea, 1);
7684
7883
 
7685
7884
  function pipelineListener(value) {
@@ -7694,7 +7893,13 @@ function inputTextareaDirective($mdUtil, $window, $mdAria) {
7694
7893
  onChangeTextarea();
7695
7894
  }
7696
7895
  element.on('keydown input', onChangeTextarea);
7697
- element.on('scroll', onScroll);
7896
+
7897
+ if(isNaN(min_rows)) {
7898
+ element.attr('rows', '1');
7899
+
7900
+ element.on('scroll', onScroll);
7901
+ }
7902
+
7698
7903
  angular.element($window).on('resize', onChangeTextarea);
7699
7904
 
7700
7905
  scope.$on('$destroy', function() {
@@ -7702,10 +7907,35 @@ function inputTextareaDirective($mdUtil, $window, $mdAria) {
7702
7907
  });
7703
7908
 
7704
7909
  function growTextarea() {
7705
- node.style.height = "auto";
7706
- node.scrollTop = 0;
7707
- var height = getHeight();
7708
- if (height) node.style.height = height + 'px';
7910
+ // sets the md-input-container height to avoid jumping around
7911
+ container.style.height = container.offsetHeight + 'px';
7912
+
7913
+ // temporarily disables element's flex so its height 'runs free'
7914
+ element.addClass('md-no-flex');
7915
+
7916
+ if(isNaN(min_rows)) {
7917
+ node.style.height = "auto";
7918
+ node.scrollTop = 0;
7919
+ var height = getHeight();
7920
+ if (height) node.style.height = height + 'px';
7921
+ } else {
7922
+ node.setAttribute("rows", 1);
7923
+
7924
+ if(!lineHeight) {
7925
+ node.style.minHeight = '0';
7926
+
7927
+ lineHeight = element.height();
7928
+
7929
+ node.style.minHeight = null;
7930
+ }
7931
+
7932
+ var rows = Math.max(min_rows, Math.round(node.scrollHeight / lineHeight));
7933
+ node.setAttribute("rows", rows);
7934
+ }
7935
+
7936
+ // reset everything back to normal
7937
+ element.removeClass('md-no-flex');
7938
+ container.style.height = 'auto';
7709
7939
  }
7710
7940
 
7711
7941
  function getHeight () {
@@ -7778,7 +8008,6 @@ function mdMaxlengthDirective($animate) {
7778
8008
  mdMaxlengthDirective.$inject = ["$animate"];
7779
8009
 
7780
8010
  function placeholderDirective($log) {
7781
- var blackListElements = ['MD-SELECT'];
7782
8011
  return {
7783
8012
  restrict: 'A',
7784
8013
  require: '^^?mdInputContainer',
@@ -7788,18 +8017,19 @@ function placeholderDirective($log) {
7788
8017
 
7789
8018
  function postLink(scope, element, attr, inputContainer) {
7790
8019
  if (!inputContainer) return;
7791
- if (blackListElements.indexOf(element[0].nodeName) != -1) return;
7792
8020
  if (angular.isDefined(inputContainer.element.attr('md-no-float'))) return;
7793
8021
 
7794
8022
  var placeholderText = attr.placeholder;
7795
8023
  element.removeAttr('placeholder');
7796
8024
 
7797
8025
  if ( inputContainer.element.find('label').length == 0 ) {
7798
- var placeholder = '<label ng-click="delegateClick()">' + placeholderText + '</label>';
8026
+ if (inputContainer.input && inputContainer.input[0].nodeName != 'MD-SELECT') {
8027
+ var placeholder = '<label ng-click="delegateClick()">' + placeholderText + '</label>';
7799
8028
 
7800
- inputContainer.element.addClass('md-icon-float');
7801
- inputContainer.element.prepend(placeholder);
7802
- } else {
8029
+ inputContainer.element.addClass('md-icon-float');
8030
+ inputContainer.element.prepend(placeholder);
8031
+ }
8032
+ } else if (element[0].nodeName != 'MD-SELECT') {
7803
8033
  $log.warn("The placeholder='" + placeholderText + "' will be ignored since this md-input-container has a child label element.");
7804
8034
  }
7805
8035
 
@@ -8103,8 +8333,9 @@ angular.module('material.components.menu', [
8103
8333
  *
8104
8334
  * Every `md-menu` must specify exactly two child elements. The first element is what is
8105
8335
  * left in the DOM and is used to open the menu. This element is called the trigger element.
8106
- * The trigger element's scope has access to `$mdOpenMenu()`
8107
- * which it may call to open the menu.
8336
+ * The trigger element's scope has access to `$mdOpenMenu($event)`
8337
+ * which it may call to open the menu. By passing $event as argument, the
8338
+ * corresponding event is stopped from propagating up the DOM-tree.
8108
8339
  *
8109
8340
  * The second element is the `md-menu-content` element which represents the
8110
8341
  * contents of the menu when it is open. Typically this will contain `md-menu-item`s,
@@ -8113,7 +8344,7 @@ angular.module('material.components.menu', [
8113
8344
  * <hljs lang="html">
8114
8345
  * <md-menu>
8115
8346
  * <!-- Trigger element is a md-button with an icon -->
8116
- * <md-button ng-click="$mdOpenMenu()" class="md-icon-button" aria-label="Open sample menu">
8347
+ * <md-button ng-click="$mdOpenMenu($event)" class="md-icon-button" aria-label="Open sample menu">
8117
8348
  * <md-icon md-svg-icon="call:phone"></md-icon>
8118
8349
  * </md-button>
8119
8350
  * <md-menu-content>
@@ -8155,7 +8386,7 @@ angular.module('material.components.menu', [
8155
8386
  *
8156
8387
  * <hljs lang="html">
8157
8388
  * <md-menu>
8158
- * <md-button ng-click="$mdOpenMenu()" class="md-icon-button" aria-label="Open some menu">
8389
+ * <md-button ng-click="$mdOpenMenu($event)" class="md-icon-button" aria-label="Open some menu">
8159
8390
  * <md-icon md-menu-origin md-svg-icon="call:phone"></md-icon>
8160
8391
  * </md-button>
8161
8392
  * <md-menu-content>
@@ -8198,7 +8429,7 @@ angular.module('material.components.menu', [
8198
8429
  * @usage
8199
8430
  * <hljs lang="html">
8200
8431
  * <md-menu>
8201
- * <md-button ng-click="$mdOpenMenu()" class="md-icon-button">
8432
+ * <md-button ng-click="$mdOpenMenu($event)" class="md-icon-button">
8202
8433
  * <md-icon md-svg-icon="call:phone"></md-icon>
8203
8434
  * </md-button>
8204
8435
  * <md-menu-content>
@@ -8238,7 +8469,6 @@ function MenuDirective($mdMenu) {
8238
8469
  }
8239
8470
 
8240
8471
  function link(scope, element, attrs, mdMenuCtrl) {
8241
-
8242
8472
  // Move everything into a md-menu-container and pass it to the controller
8243
8473
  var menuContainer = angular.element(
8244
8474
  '<div class="md-open-menu-container md-whiteframe-z2"></div>'
@@ -8272,10 +8502,13 @@ function MenuController($mdMenu, $attrs, $element, $scope) {
8272
8502
  };
8273
8503
 
8274
8504
  // Uses the $mdMenu interim element service to open the menu contents
8275
- this.open = function openMenu() {
8505
+ this.open = function openMenu(ev) {
8506
+ ev && ev.stopPropagation();
8507
+
8276
8508
  ctrl.isOpen = true;
8277
8509
  triggerElement.setAttribute('aria-expanded', 'true');
8278
8510
  $mdMenu.show({
8511
+ scope: $scope,
8279
8512
  mdMenuCtrl: ctrl,
8280
8513
  element: menuContainer,
8281
8514
  target: $element[0]
@@ -8369,6 +8602,7 @@ function MenuProvider($$interimElementProvider) {
8369
8602
  hasBackdrop: true,
8370
8603
  disableParentScroll: true,
8371
8604
  skipCompile: true,
8605
+ preserveScope: true,
8372
8606
  themable: true
8373
8607
  };
8374
8608
 
@@ -8378,7 +8612,6 @@ function MenuProvider($$interimElementProvider) {
8378
8612
  * various interaction events
8379
8613
  */
8380
8614
  function onShow(scope, element, opts) {
8381
-
8382
8615
  // Sanitize and set defaults on opts
8383
8616
  buildOpts(opts);
8384
8617
 
@@ -8467,7 +8700,9 @@ function MenuProvider($$interimElementProvider) {
8467
8700
  opts.backdrop && opts.backdrop.on('click', function(e) {
8468
8701
  e.preventDefault();
8469
8702
  e.stopPropagation();
8470
- opts.mdMenuCtrl.close(true);
8703
+ scope.$apply(function() {
8704
+ opts.mdMenuCtrl.close(true);
8705
+ });
8471
8706
  });
8472
8707
 
8473
8708
  // Wire up keyboard listeners.
@@ -8483,25 +8718,36 @@ function MenuProvider($$interimElementProvider) {
8483
8718
  });
8484
8719
 
8485
8720
  // Close menu on menu item click, if said menu-item is not disabled
8486
- opts.menuContentEl.on('click', function(e) {
8721
+ opts.menuContentEl[0].addEventListener('click', function(e) {
8487
8722
  var target = e.target;
8488
8723
  // Traverse up the event until we get to the menuContentEl to see if
8489
8724
  // there is an ng-click and that the ng-click is not disabled
8490
8725
  do {
8491
- if (target && target.hasAttribute('ng-click')) {
8726
+ if (target == opts.menuContentEl[0]) return;
8727
+ if (hasAnyAttribute(target, ['ng-click', 'data-ng-click', 'x-ng-click'])) {
8492
8728
  if (!target.hasAttribute('disabled')) {
8493
8729
  close();
8494
8730
  }
8495
8731
  break;
8496
8732
  }
8497
- } while ((target = target.parentNode) && target != opts.menuContentEl)
8733
+ } while (target = target.parentNode)
8498
8734
 
8499
8735
  function close() {
8500
8736
  scope.$apply(function() {
8501
8737
  opts.mdMenuCtrl.close();
8502
8738
  });
8503
8739
  }
8504
- });
8740
+
8741
+ function hasAnyAttribute(target, attrs) {
8742
+ if (!target) return false;
8743
+ for (var i = 0, attr; attr = attrs[i]; ++i) {
8744
+ if (target.hasAttribute(attr)) {
8745
+ return true;
8746
+ }
8747
+ }
8748
+ return false;
8749
+ }
8750
+ }, true);
8505
8751
 
8506
8752
  // kick off initial focus in the menu on the first element
8507
8753
  var focusTarget = opts.menuContentEl[0].querySelector('[md-menu-focus-target]');
@@ -8598,8 +8844,8 @@ function MenuProvider($$interimElementProvider) {
8598
8844
 
8599
8845
  var bounds = {
8600
8846
  left: boundryNodeRect.left + MENU_EDGE_MARGIN,
8601
- top: boundryNodeRect.top + MENU_EDGE_MARGIN,
8602
- bottom: boundryNodeRect.bottom - MENU_EDGE_MARGIN,
8847
+ top: Math.max(boundryNodeRect.top, 0) + MENU_EDGE_MARGIN,
8848
+ bottom: Math.max(boundryNodeRect.bottom, Math.max(boundryNodeRect.top, 0) + boundryNodeRect.height) - MENU_EDGE_MARGIN,
8603
8849
  right: boundryNodeRect.right - MENU_EDGE_MARGIN
8604
8850
  };
8605
8851
 
@@ -9272,57 +9518,51 @@ angular.module('material.components.select', [
9272
9518
  * @description Displays a select box, bound to an ng-model.
9273
9519
  *
9274
9520
  * @param {expression} ng-model The model!
9275
- * @param {expression=} md-on-close expression to be evaluated when the select is closed
9276
9521
  * @param {boolean=} multiple Whether it's multiple.
9522
+ * @param {expression=} md-on-close expression to be evaluated when the select is closed
9277
9523
  * @param {string=} placeholder Placeholder hint text.
9278
9524
  * @param {string=} aria-label Optional label for accessibility. Only necessary if no placeholder or
9525
+ * @param {string=} md-container-class class list to get applied to the .md-select-menu-container element (for custom styling)
9279
9526
  * explicit label is present.
9280
9527
  *
9281
9528
  * @usage
9282
9529
  * With a placeholder (label and aria-label are added dynamically)
9283
9530
  * <hljs lang="html">
9284
- * <md-select
9285
- * ng-model="someModel"
9286
- * placeholder="Select a state">
9287
- * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
9288
- * </md-select>
9531
+ * <md-input-container>
9532
+ * <md-select
9533
+ * ng-model="someModel"
9534
+ * placeholder="Select a state">
9535
+ * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
9536
+ * </md-select>
9537
+ * </md-input-container>
9289
9538
  * </hljs>
9290
9539
  *
9291
9540
  * With an explicit label
9292
9541
  * <hljs lang="html">
9293
- * <md-select
9294
- * ng-model="someModel">
9295
- * <md-select-label>Select a state</md-select-label>
9296
- * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
9297
- * </md-select>
9542
+ * <md-input-container>
9543
+ * <label>State</label>
9544
+ * <md-select
9545
+ * ng-model="someModel">
9546
+ * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
9547
+ * </md-select>
9548
+ * </md-input-container>
9298
9549
  * </hljs>
9299
9550
  */
9300
9551
  function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate, $compile, $parse) {
9301
9552
  return {
9302
9553
  restrict: 'E',
9303
- require: ['mdSelect', 'ngModel', '?^form'],
9554
+ require: ['^?mdInputContainer', 'mdSelect', 'ngModel', '?^form'],
9304
9555
  compile: compile,
9305
9556
  controller: function() { } // empty placeholder controller to be initialized in link
9306
9557
  };
9307
9558
 
9308
9559
  function compile(element, attr) {
9309
- // The user is allowed to provide a label for the select as md-select-label child
9310
- var labelEl = element.find('md-select-label').remove();
9311
-
9312
- // If not provided, we automatically make one
9313
- if (!labelEl.length) {
9314
- labelEl = angular.element('<md-select-label><span></span></md-select-label>');
9315
- } else {
9316
- if (!labelEl[0].firstElementChild) {
9317
- var spanWrapper = angular.element('<span>');
9318
- spanWrapper.append(labelEl.contents());
9319
- labelEl.append(spanWrapper);
9320
- }
9321
- }
9322
- labelEl.append('<span class="md-select-icon" aria-hidden="true"></span>');
9323
- labelEl.addClass('md-select-label');
9324
- if (!labelEl[0].hasAttribute('id')) {
9325
- labelEl.attr('id', 'select_label_' + $mdUtil.nextUid());
9560
+ // add the select value that will hold our placeholder or selected option value
9561
+ var valueEl = angular.element('<md-select-value><span></span></md-select-value>');
9562
+ valueEl.append('<span class="md-select-icon" aria-hidden="true"></span>');
9563
+ valueEl.addClass('md-select-value');
9564
+ if (!valueEl[0].hasAttribute('id')) {
9565
+ valueEl.attr('id', 'select_value_label_' + $mdUtil.nextUid());
9326
9566
  }
9327
9567
 
9328
9568
  // There's got to be an md-content inside. If there's not one, let's add it.
@@ -9367,7 +9607,7 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9367
9607
  element.html() +
9368
9608
  '</md-select-menu></div>';
9369
9609
 
9370
- element.empty().append(labelEl);
9610
+ element.empty().append(valueEl);
9371
9611
 
9372
9612
  attr.tabindex = attr.tabindex || '0';
9373
9613
 
@@ -9375,12 +9615,30 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9375
9615
  var isOpen;
9376
9616
  var isDisabled;
9377
9617
 
9378
- var mdSelectCtrl = ctrls[0];
9379
- var ngModel = ctrls[1];
9380
- var formCtrl = ctrls[2];
9618
+ var containerCtrl = ctrls[0];
9619
+ var mdSelectCtrl = ctrls[1];
9620
+ var ngModelCtrl = ctrls[2];
9621
+ var formCtrl = ctrls[3];
9622
+ // grab a reference to the select menu value label
9623
+ var valueEl = element.find('md-select-value');
9624
+ var isReadonly = angular.isDefined(attr.readonly);
9625
+
9626
+ if (containerCtrl) {
9627
+ if (containerCtrl.input) {
9628
+ throw new Error("<md-input-container> can only have *one* child <input>, <textarea> or <select> element!");
9629
+ }
9630
+ containerCtrl.input = element;
9631
+ if (!containerCtrl.label) {
9632
+ $mdAria.expect(element, 'aria-label', element.attr('placeholder'));
9633
+ }
9634
+
9635
+ var isErrorGetter = containerCtrl && containerCtrl.isErrorGetter || function() {
9636
+ return ngModelCtrl.$invalid && ngModelCtrl.$touched;
9637
+ };
9638
+ scope.$watch(isErrorGetter, containerCtrl.setInvalid);
9639
+ }
9640
+
9381
9641
 
9382
- var labelEl = element.find('md-select-label');
9383
- var customLabel = labelEl.text().length !== 0;
9384
9642
  var selectContainer, selectScope, selectMenuCtrl;
9385
9643
  createSelect();
9386
9644
 
@@ -9391,24 +9649,52 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9391
9649
  formCtrl.$removeControl(angular.element(selectEl).controller());
9392
9650
  }
9393
9651
 
9394
- var originalRender = ngModel.$render;
9395
- ngModel.$render = function() {
9652
+
9653
+ var originalRender = ngModelCtrl.$render;
9654
+ ngModelCtrl.$render = function() {
9396
9655
  originalRender();
9397
9656
  syncLabelText();
9657
+ inputCheckValue();
9398
9658
  };
9399
9659
 
9400
9660
  mdSelectCtrl.setLabelText = function(text) {
9401
- if (customLabel) return; // Assume that user is handling it on their own
9402
9661
  mdSelectCtrl.setIsPlaceholder(!text);
9403
- text = text || attr.placeholder || '';
9404
- var target = customLabel ? labelEl : labelEl.children().eq(0);
9662
+ // Use placeholder attribute, otherwise fallback to the md-input-container label
9663
+ var tmpPlaceholder = attr.placeholder || (containerCtrl && containerCtrl.label ? containerCtrl.label.text() : '');
9664
+ text = text || tmpPlaceholder || '';
9665
+ var target = valueEl.children().eq(0);
9405
9666
  target.text(text);
9406
9667
  };
9407
9668
 
9408
- mdSelectCtrl.setIsPlaceholder = function(val) {
9409
- val ? labelEl.addClass('md-placeholder') : labelEl.removeClass('md-placeholder');
9669
+ mdSelectCtrl.setIsPlaceholder = function(isPlaceholder) {
9670
+ if (isPlaceholder) {
9671
+ valueEl.addClass('md-select-placeholder');
9672
+ if (containerCtrl && containerCtrl.label) {
9673
+ containerCtrl.label.addClass('md-placeholder md-static');
9674
+ }
9675
+ } else {
9676
+ valueEl.removeClass('md-select-placeholder');
9677
+ if (containerCtrl && containerCtrl.label) {
9678
+ containerCtrl.label.removeClass('md-placeholder');
9679
+ }
9680
+ }
9410
9681
  };
9411
9682
 
9683
+ if (!isReadonly) {
9684
+ element
9685
+ .on('focus', function(ev) {
9686
+ // only set focus on if we don't currently have a selected value. This avoids the "bounce"
9687
+ // on the label transition because the focus will immediately switch to the open menu.
9688
+ if (containerCtrl && containerCtrl.element.hasClass('md-input-has-value')) {
9689
+ containerCtrl.setFocused(true);
9690
+ }
9691
+ })
9692
+ .on('blur', function(ev) {
9693
+ containerCtrl && containerCtrl.setFocused(false);
9694
+ inputCheckValue();
9695
+ });
9696
+ }
9697
+
9412
9698
  mdSelectCtrl.triggerClose = function() {
9413
9699
  $parse(attr.mdOnClose)(scope);
9414
9700
  };
@@ -9420,8 +9706,8 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9420
9706
 
9421
9707
  function setAriaLabel() {
9422
9708
  var labelText = element.attr('placeholder');
9423
- if (!labelText) {
9424
- labelText = element.find('md-select-label').text();
9709
+ if (!labelText && containerCtrl && containerCtrl.label) {
9710
+ labelText = containerCtrl.label.text();
9425
9711
  }
9426
9712
  $mdAria.expect(element, 'aria-label', labelText);
9427
9713
  }
@@ -9446,13 +9732,13 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9446
9732
  }
9447
9733
  if (selectContainer) {
9448
9734
  selectMenuCtrl.setMultiple(multiple);
9449
- originalRender = ngModel.$render;
9450
- ngModel.$render = function() {
9735
+ originalRender = ngModelCtrl.$render;
9736
+ ngModelCtrl.$render = function() {
9451
9737
  originalRender();
9452
9738
  syncLabelText();
9453
9739
  };
9454
9740
  selectMenuCtrl.refreshViewValue();
9455
- ngModel.$render();
9741
+ ngModelCtrl.$render();
9456
9742
  }
9457
9743
  });
9458
9744
  });
@@ -9500,16 +9786,28 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9500
9786
  } else {
9501
9787
  selectContainer.remove();
9502
9788
  }
9789
+ if (containerCtrl) {
9790
+ containerCtrl.setFocused(false);
9791
+ containerCtrl.setHasValue(false);
9792
+ containerCtrl.input = null;
9793
+ }
9503
9794
  });
9504
9795
 
9796
+ function inputCheckValue() {
9797
+ // The select counts as having a value if one or more options are selected,
9798
+ // or if the input's validity state says it has bad input (eg string in a number input)
9799
+ containerCtrl && containerCtrl.setHasValue(selectMenuCtrl.selectedLabels().length > 0 || (element[0].validity || {}).badInput);
9800
+ }
9505
9801
 
9506
9802
  // Create a fake select to find out the label value
9507
9803
  function createSelect() {
9508
9804
  selectContainer = angular.element(selectTemplate);
9509
9805
  var selectEl = selectContainer.find('md-select-menu');
9510
- selectEl.data('$ngModelController', ngModel);
9806
+ selectEl.data('$ngModelController', ngModelCtrl);
9511
9807
  selectEl.data('$mdSelectController', mdSelectCtrl);
9512
9808
  selectScope = scope.$new();
9809
+ $mdTheming.inherit(selectContainer, element);
9810
+ selectContainer[0].setAttribute('class', selectContainer[0].getAttribute('class') + ' ' + element.attr('md-container-class'));
9513
9811
  selectContainer = $compile(selectContainer)(selectScope);
9514
9812
  selectMenuCtrl = selectContainer.find('md-select-menu').controller('mdSelectMenu');
9515
9813
  }
@@ -9531,7 +9829,7 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9531
9829
  }
9532
9830
  selectMenuCtrl.select(optionCtrl.hashKey, optionCtrl.value);
9533
9831
  selectMenuCtrl.refreshViewValue();
9534
- ngModel.$render();
9832
+ ngModelCtrl.$render();
9535
9833
  }
9536
9834
  }
9537
9835
  }
@@ -9546,7 +9844,7 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate,
9546
9844
  element: selectContainer,
9547
9845
  target: element[0],
9548
9846
  hasBackdrop: true,
9549
- loadingAsync: attr.mdOnOpen ? scope.$eval(attr.mdOnOpen) || true : false,
9847
+ loadingAsync: attr.mdOnOpen ? scope.$eval(attr.mdOnOpen) || true : false
9550
9848
  }).then(function(selectedText) {
9551
9849
  isOpen = false;
9552
9850
  });
@@ -9597,6 +9895,10 @@ function SelectMenuDirective($parse, $mdUtil, $mdTheming) {
9597
9895
  var option = $mdUtil.getClosest(ev.target, 'md-option');
9598
9896
  var optionCtrl = option && angular.element(option).data('$mdOptionController');
9599
9897
  if (!option || !optionCtrl) return;
9898
+ if (option.hasAttribute('disabled')) {
9899
+ ev.stopImmediatePropagation();
9900
+ return false;
9901
+ }
9600
9902
 
9601
9903
  var optionHashKey = selectCtrl.hashGetter(optionCtrl.value);
9602
9904
  var isSelected = angular.isDefined(selectCtrl.selected[optionHashKey]);
@@ -9828,9 +10130,18 @@ function OptionDirective($mdButtonInkRipple, $mdUtil) {
9828
10130
  scope.$watch(function() { return element.text(); }, setOptionValue);
9829
10131
  }
9830
10132
 
10133
+ attr.$observe('disabled', function(disabled) {
10134
+ if (disabled) {
10135
+ element.attr('tabindex', '-1');
10136
+ } else {
10137
+ element.attr('tabindex', '0');
10138
+ }
10139
+ });
10140
+
9831
10141
  scope.$$postDigest(function() {
9832
10142
  attr.$observe('selected', function(selected) {
9833
10143
  if (!angular.isDefined(selected)) return;
10144
+ if (typeof selected == 'string') selected = true;
9834
10145
  if (selected) {
9835
10146
  if (!selectCtrl.isMultiple) {
9836
10147
  selectCtrl.deselect( Object.keys(selectCtrl.selected)[0] );
@@ -9987,7 +10298,7 @@ function SelectProvider($$interimElementProvider) {
9987
10298
  $timeout(activateInteraction, 75, false);
9988
10299
 
9989
10300
  if (opts.backdrop) {
9990
- $mdTheming.inherit(opts.backdrop, opts.parent);
10301
+ $mdTheming.inherit(opts.backdrop, opts.target);
9991
10302
  opts.parent.append(opts.backdrop);
9992
10303
  }
9993
10304
  opts.parent.append(element);
@@ -10049,6 +10360,7 @@ function SelectProvider($$interimElementProvider) {
10049
10360
  default:
10050
10361
  if (ev.keyCode >= 31 && ev.keyCode <= 90) {
10051
10362
  var optNode = opts.selectEl.controller('mdSelectMenu').optNodeForKeyboardSearch(ev);
10363
+ opts.focusedNode = optNode || opts.focusedNode;
10052
10364
  optNode && optNode.focus();
10053
10365
  }
10054
10366
  }
@@ -10056,18 +10368,27 @@ function SelectProvider($$interimElementProvider) {
10056
10368
 
10057
10369
 
10058
10370
  function focusOption(direction) {
10371
+ optionNodes = opts.selectEl[0].getElementsByTagName('md-option');
10372
+
10059
10373
  var optionsArray = $mdUtil.nodesToArray(optionNodes);
10060
10374
  var index = optionsArray.indexOf(opts.focusedNode);
10061
- if (index === -1) {
10062
- // We lost the previously focused element, reset to first option
10063
- index = 0;
10064
- } else if (direction === 'next' && index < optionsArray.length - 1) {
10065
- index++;
10066
- } else if (direction === 'prev' && index > 0) {
10067
- index--;
10068
- }
10069
- var newOption = opts.focusedNode = optionsArray[index];
10375
+
10376
+ var newOption;
10377
+
10378
+ do {
10379
+ if (index === -1) {
10380
+ // We lost the previously focused element, reset to first option
10381
+ index = 0;
10382
+ } else if (direction === 'next' && index < optionsArray.length - 1) {
10383
+ index++;
10384
+ } else if (direction === 'prev' && index > 0) {
10385
+ index--;
10386
+ }
10387
+ newOption = optionsArray[index];
10388
+ if (newOption.hasAttribute('disabled')) newOption = undefined;
10389
+ } while (!newOption && index < optionsArray.length - 1 && index > 0)
10070
10390
  newOption && newOption.focus();
10391
+ opts.focusedNode = newOption;
10071
10392
  }
10072
10393
  function focusNextOption() {
10073
10394
  focusOption('next');
@@ -10096,11 +10417,13 @@ function SelectProvider($$interimElementProvider) {
10096
10417
  }
10097
10418
 
10098
10419
  function onRemove(scope, element, opts) {
10099
- opts.isRemoved = true;
10100
- element.addClass('md-leave')
10420
+ element
10421
+ .addClass('md-leave')
10101
10422
  .removeClass('md-clickable');
10102
- opts.target.attr('aria-expanded', 'false');
10103
10423
 
10424
+ opts.target.attr('aria-expanded', 'false');
10425
+ opts.selectEl.off('keydown');
10426
+ opts.isRemoved = true;
10104
10427
 
10105
10428
  angular.element($window).off('resize', opts.resizeFn);
10106
10429
  angular.element($window).off('orientationchange', opts.resizefn);
@@ -10127,7 +10450,7 @@ function SelectProvider($$interimElementProvider) {
10127
10450
 
10128
10451
  function animateSelect(scope, element, opts) {
10129
10452
  var containerNode = element[0],
10130
- targetNode = opts.target[0].firstElementChild.firstElementChild, // target the first span, functioning as the label
10453
+ targetNode = opts.target[0].firstElementChild, // target the label
10131
10454
  parentNode = opts.parent[0],
10132
10455
  selectNode = opts.selectEl[0],
10133
10456
  contentNode = opts.contentEl[0],
@@ -10249,7 +10572,7 @@ function SelectProvider($$interimElementProvider) {
10249
10572
  $$rAF(function() {
10250
10573
  element.addClass('md-active');
10251
10574
  selectNode.style[$mdConstant.CSS.TRANSFORM] = '';
10252
- if (focusedNode) {
10575
+ if (focusedNode && !focusedNode.hasAttribute('disabled')) {
10253
10576
  opts.focusedNode = focusedNode;
10254
10577
  focusedNode.focus();
10255
10578
  }
@@ -10743,7 +11066,7 @@ SidenavController.$inject = ["$scope", "$element", "$attrs", "$mdComponentRegist
10743
11066
  * @param {number=} min The minimum value the user is allowed to pick. Default 0.
10744
11067
  * @param {number=} max The maximum value the user is allowed to pick. Default 100.
10745
11068
  */
10746
- function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdTheming, $mdGesture, $parse) {
11069
+ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdTheming, $mdGesture, $parse, $log) {
10747
11070
  return {
10748
11071
  scope: {},
10749
11072
  require: '?ngModel',
@@ -10882,15 +11205,24 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
10882
11205
  var tickCanvas, tickCtx;
10883
11206
  function redrawTicks() {
10884
11207
  if (!angular.isDefined(attr.mdDiscrete)) return;
11208
+ if ( angular.isUndefined(step) ) return;
11209
+
11210
+ if ( step <= 0 ) {
11211
+ var msg = 'Slider step value must be greater than zero when in discrete mode';
11212
+ $log.error(msg);
11213
+ throw new Error(msg);
11214
+ }
10885
11215
 
10886
11216
  var numSteps = Math.floor( (max - min) / step );
10887
11217
  if (!tickCanvas) {
10888
- var trackTicksStyle = $window.getComputedStyle(tickContainer[0]);
10889
11218
  tickCanvas = angular.element('<canvas style="position:absolute;">');
11219
+ tickContainer.append(tickCanvas);
11220
+
11221
+ var trackTicksStyle = $window.getComputedStyle(tickContainer[0]);
10890
11222
  tickCtx = tickCanvas[0].getContext('2d');
10891
11223
  tickCtx.fillStyle = trackTicksStyle.backgroundColor || 'black';
10892
- tickContainer.append(tickCanvas);
10893
11224
  }
11225
+
10894
11226
  var dimensions = getSliderDimensions();
10895
11227
  tickCanvas[0].width = dimensions.width;
10896
11228
  tickCanvas[0].height = dimensions.height;
@@ -11088,7 +11420,7 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
11088
11420
  }
11089
11421
  }
11090
11422
  }
11091
- SliderDirective.$inject = ["$$rAF", "$window", "$mdAria", "$mdUtil", "$mdConstant", "$mdTheming", "$mdGesture", "$parse"];
11423
+ SliderDirective.$inject = ["$$rAF", "$window", "$mdAria", "$mdUtil", "$mdConstant", "$mdTheming", "$mdGesture", "$parse", "$log"];
11092
11424
 
11093
11425
  })();
11094
11426
  (function(){
@@ -11831,7 +12163,7 @@ function MdToastDirective() {
11831
12163
  * - $mdToastPreset#action(string) - adds an action button, which resolves the promise returned from `show()` if clicked.
11832
12164
  * - $mdToastPreset#highlightAction(boolean) - sets action button to be highlighted
11833
12165
  * - $mdToastPreset#capsule(boolean) - adds 'md-capsule' class to the toast (curved corners)
11834
- * - $mdToastPreset#theme(boolean) - sets the theme on the toast to theme (default is `$mdThemingProvider`'s default theme)
12166
+ * - $mdToastPreset#theme(string) - sets the theme on the toast to theme (default is `$mdThemingProvider`'s default theme)
11835
12167
  */
11836
12168
 
11837
12169
  /**
@@ -12205,7 +12537,7 @@ angular
12205
12537
  *
12206
12538
  * @param {expression=} md-visible Boolean bound to whether the tooltip is
12207
12539
  * currently visible.
12208
- * @param {number=} md-delay How many milliseconds to wait to show the tooltip after the user focuses, hovers, or touches the parent. Defaults to 400ms.
12540
+ * @param {number=} md-delay How many milliseconds to wait to show the tooltip after the user focuses, hovers, or touches the parent. Defaults to 300ms.
12209
12541
  * @param {string=} md-direction Which direction would you like the tooltip to go? Supports left, right, top, and bottom. Defaults to bottom.
12210
12542
  * @param {boolean=} md-autohide If present or provided with a boolean value, the tooltip will hide on mouse leave, regardless of focus
12211
12543
  */
@@ -12242,195 +12574,879 @@ function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdThe
12242
12574
  tooltipParent = angular.element(current || document.body),
12243
12575
  debouncedOnResize = $$rAF.throttle(function () { if (scope.visible) positionTooltip(); });
12244
12576
 
12245
- return init();
12577
+ // Initialize element
12578
+
12579
+ setDefaults();
12580
+ manipulateElement();
12581
+ bindEvents();
12582
+ configureWatchers();
12583
+ addAriaLabel();
12584
+
12585
+
12586
+ function setDefaults () {
12587
+ if (!angular.isDefined(attr.mdDelay)) scope.delay = TOOLTIP_SHOW_DELAY;
12588
+ }
12589
+
12590
+ function configureWatchers () {
12591
+ scope.$on('$destroy', function() {
12592
+ scope.visible = false;
12593
+ element.remove();
12594
+ angular.element($window).off('resize', debouncedOnResize);
12595
+ });
12596
+ scope.$watch('visible', function (isVisible) {
12597
+ if (isVisible) showTooltip();
12598
+ else hideTooltip();
12599
+ });
12600
+ }
12601
+
12602
+ function addAriaLabel () {
12603
+ if (!parent.attr('aria-label') && !parent.text().trim()) {
12604
+ parent.attr('aria-label', element.text().trim());
12605
+ }
12606
+ }
12607
+
12608
+ function manipulateElement () {
12609
+ element.detach();
12610
+ element.attr('role', 'tooltip');
12611
+ }
12612
+
12613
+ /**
12614
+ * Scan up dom hierarchy for enabled parent;
12615
+ */
12616
+ function getParentWithPointerEvents () {
12617
+ var parent = element.parent();
12618
+ while (parent && hasComputedStyleValue('pointer-events','none', parent[0])) {
12619
+ parent = parent.parent();
12620
+ }
12621
+ return parent;
12622
+ }
12623
+
12624
+ function getNearestContentElement () {
12625
+ var current = element.parent()[0];
12626
+ // Look for the nearest parent md-content, stopping at the rootElement.
12627
+ while (current && current !== $rootElement[0] && current !== document.body) {
12628
+ current = current.parentNode;
12629
+ }
12630
+ return current;
12631
+ }
12632
+
12633
+
12634
+ function hasComputedStyleValue(key, value, target) {
12635
+ key = attr.$normalize(key);
12636
+ target = target || element[0];
12637
+
12638
+ var computedStyles = $window.getComputedStyle(target);
12639
+
12640
+ return angular.isDefined(computedStyles[key]) && (computedStyles[key] == value);
12641
+ }
12642
+
12643
+ function bindEvents () {
12644
+ var mouseActive = false;
12645
+ var enterHandler = function() {
12646
+ parent.on('blur mouseleave touchend touchcancel', leaveHandler );
12647
+ setVisible(true);
12648
+ };
12649
+ var leaveHandler = function () {
12650
+ var autohide = scope.hasOwnProperty('autohide') ? scope.autohide : attr.hasOwnProperty('mdAutohide');
12651
+ if (autohide || mouseActive || ($document[0].activeElement !== parent[0]) ) {
12652
+ parent.off('blur mouseleave touchend touchcancel', leaveHandler );
12653
+ setVisible(false);
12654
+ }
12655
+ mouseActive = false;
12656
+ };
12657
+
12658
+ // to avoid `synthetic clicks` we listen to mousedown instead of `click`
12659
+ parent.on('mousedown', function() { mouseActive = true; });
12660
+ parent.on('focus mouseenter touchstart', enterHandler );
12661
+
12662
+
12663
+ angular.element($window).on('resize', debouncedOnResize);
12664
+ }
12665
+
12666
+ function setVisible (value) {
12667
+ setVisible.value = !!value;
12668
+ if (!setVisible.queued) {
12669
+ if (value) {
12670
+ setVisible.queued = true;
12671
+ $timeout(function() {
12672
+ scope.visible = setVisible.value;
12673
+ setVisible.queued = false;
12674
+ }, scope.delay);
12675
+ } else {
12676
+ $timeout(function() { scope.visible = false; });
12677
+ }
12678
+ }
12679
+ }
12680
+
12681
+ function showTooltip() {
12682
+ // Insert the element before positioning it, so we can get the position
12683
+ // and check if we should display it
12684
+ tooltipParent.append(element);
12685
+
12686
+ // Check if we should display it or not.
12687
+ // This handles hide-* and show-* along with any user defined css
12688
+ if ( hasComputedStyleValue('display','none') ) {
12689
+ scope.visible = false;
12690
+ element.detach();
12691
+ return;
12692
+ }
12693
+
12694
+ positionTooltip();
12695
+ angular.forEach([element, background, content], function (element) {
12696
+ $animate.addClass(element, 'md-show');
12697
+ });
12698
+ }
12699
+
12700
+ function hideTooltip() {
12701
+ $q.all([
12702
+ $animate.removeClass(content, 'md-show'),
12703
+ $animate.removeClass(background, 'md-show'),
12704
+ $animate.removeClass(element, 'md-show')
12705
+ ]).then(function () {
12706
+ if (!scope.visible) element.detach();
12707
+ });
12708
+ }
12709
+
12710
+ function positionTooltip() {
12711
+ var tipRect = $mdUtil.offsetRect(element, tooltipParent);
12712
+ var parentRect = $mdUtil.offsetRect(parent, tooltipParent);
12713
+ var newPosition = getPosition(direction);
12714
+
12715
+ // If the user provided a direction, just nudge the tooltip onto the screen
12716
+ // Otherwise, recalculate based on 'top' since default is 'bottom'
12717
+ if (direction) {
12718
+ newPosition = fitInParent(newPosition);
12719
+ } else if (newPosition.top > element.prop('offsetParent').scrollHeight - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE) {
12720
+ newPosition = fitInParent(getPosition('top'));
12721
+ }
12722
+
12723
+ element.css({top: newPosition.top + 'px', left: newPosition.left + 'px'});
12724
+
12725
+ positionBackground();
12726
+
12727
+ function positionBackground () {
12728
+ var size = direction === 'left' || direction === 'right'
12729
+ ? Math.sqrt(Math.pow(tipRect.width, 2) + Math.pow(tipRect.height / 2, 2)) * 2
12730
+ : Math.sqrt(Math.pow(tipRect.width / 2, 2) + Math.pow(tipRect.height, 2)) * 2,
12731
+ position = direction === 'left' ? { left: 100, top: 50 }
12732
+ : direction === 'right' ? { left: 0, top: 50 }
12733
+ : direction === 'top' ? { left: 50, top: 100 }
12734
+ : { left: 50, top: 0 };
12735
+ background.css({
12736
+ width: size + 'px',
12737
+ height: size + 'px',
12738
+ left: position.left + '%',
12739
+ top: position.top + '%'
12740
+ });
12741
+ }
12742
+
12743
+ function fitInParent (pos) {
12744
+ var newPosition = { left: pos.left, top: pos.top };
12745
+ newPosition.left = Math.min( newPosition.left, tooltipParent.prop('scrollWidth') - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE );
12746
+ newPosition.left = Math.max( newPosition.left, TOOLTIP_WINDOW_EDGE_SPACE );
12747
+ newPosition.top = Math.min( newPosition.top, tooltipParent.prop('scrollHeight') - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE );
12748
+ newPosition.top = Math.max( newPosition.top, TOOLTIP_WINDOW_EDGE_SPACE );
12749
+ return newPosition;
12750
+ }
12751
+
12752
+ function getPosition (dir) {
12753
+ return dir === 'left'
12754
+ ? { left: parentRect.left - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE,
12755
+ top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
12756
+ : dir === 'right'
12757
+ ? { left: parentRect.left + parentRect.width + TOOLTIP_WINDOW_EDGE_SPACE,
12758
+ top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
12759
+ : dir === 'top'
12760
+ ? { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
12761
+ top: parentRect.top - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE }
12762
+ : { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
12763
+ top: parentRect.top + parentRect.height + TOOLTIP_WINDOW_EDGE_SPACE };
12764
+ }
12765
+ }
12766
+
12767
+ }
12768
+
12769
+ }
12770
+ MdTooltipDirective.$inject = ["$timeout", "$window", "$$rAF", "$document", "$mdUtil", "$mdTheming", "$rootElement", "$animate", "$q"];
12771
+
12772
+ })();
12773
+ (function(){
12774
+ "use strict";
12775
+
12776
+ /**
12777
+ * @ngdoc module
12778
+ * @name material.components.virtualRepeat
12779
+ */
12780
+ angular.module('material.components.virtualRepeat', [
12781
+ 'material.core'
12782
+ ])
12783
+ .directive('mdVirtualRepeatContainer', VirtualRepeatContainerDirective)
12784
+ .directive('mdVirtualRepeat', VirtualRepeatDirective);
12785
+
12786
+
12787
+ /**
12788
+ * @ngdoc directive
12789
+ * @name mdVirtualRepeatContainer
12790
+ * @module material.components.virtualRepeat
12791
+ * @restrict E
12792
+ * @description
12793
+ * `md-virtual-repeat-container` provides the scroll container for md-virtual-repeat.
12794
+ *
12795
+ * Virtual repeat is a limited substitute for ng-repeat that renders only
12796
+ * enough dom nodes to fill the container and recycling them as the user scrolls.
12797
+ *
12798
+ * @usage
12799
+ * <hljs lang="html">
12800
+ *
12801
+ * <md-virtual-repeat-container>
12802
+ * <div md-virtual-repeat="i in items" md-item-size="20">Hello {{i}}!</div>
12803
+ * </md-virtual-repeat-container>
12804
+ * </hljs>
12805
+ *
12806
+ * @param {boolean=} md-orient-horizontal Whether the container should scroll horizontally
12807
+ * (defaults to orientation and scrolling vertically).
12808
+ * @param {boolean=} md-auto-shrink When present, the container will shrink to fit
12809
+ * the number of items when that number is less than its original size.
12810
+ * @param {number=} md-auto-shrink-min Minimum number of items that md-auto-shrink
12811
+ * will shrink to (default: 0).
12812
+ */
12813
+ function VirtualRepeatContainerDirective() {
12814
+ return {
12815
+ controller: VirtualRepeatContainerController,
12816
+ restrict: 'E',
12817
+ template: virtualRepeatContainerTemplate,
12818
+ compile: function virtualRepeatContainerCompile($element, $attrs) {
12819
+ $element
12820
+ .addClass('md-virtual-repeat-container')
12821
+ .addClass($attrs.hasOwnProperty('mdOrientHorizontal')
12822
+ ? 'md-orient-horizontal'
12823
+ : 'md-orient-vertical');
12824
+ }
12825
+ };
12826
+ }
12827
+
12828
+
12829
+ function virtualRepeatContainerTemplate($element) {
12830
+ return '<div class="md-virtual-repeat-scroller">' +
12831
+ '<div class="md-virtual-repeat-sizer"></div>' +
12832
+ '<div class="md-virtual-repeat-offsetter">' +
12833
+ $element[0].innerHTML +
12834
+ '</div></div>';
12835
+ }
12836
+
12837
+ /**
12838
+ * Maximum size, in pixels, that can be explicitly set to an element. The actual value varies
12839
+ * between browsers, but IE11 has the very lowest size at a mere 1,533,917px. Ideally we could
12840
+ * *compute* this value, but Firefox always reports an element to have a size of zero if it
12841
+ * goes over the max, meaning that we'd have to binary search for the value.
12842
+ * @const {number}
12843
+ */
12844
+ var MAX_ELEMENT_SIZE = 1533917;
12845
+
12846
+ /**
12847
+ * Number of additional elements to render above and below the visible area inside
12848
+ * of the virtual repeat container. A higher number results in less flicker when scrolling
12849
+ * very quickly in Safari, but comes with a higher rendering and dirty-checking cost.
12850
+ * @const {number}
12851
+ */
12852
+ var NUM_EXTRA = 3;
12853
+
12854
+ /** @ngInject */
12855
+ function VirtualRepeatContainerController($$rAF, $scope, $element, $attrs) {
12856
+ this.$scope = $scope;
12857
+ this.$element = $element;
12858
+ this.$attrs = $attrs;
12859
+
12860
+ /** @type {number} The width or height of the container */
12861
+ this.size = 0;
12862
+ /** @type {number} The scroll width or height of the scroller */
12863
+ this.scrollSize = 0;
12864
+ /** @type {number} The scrollLeft or scrollTop of the scroller */
12865
+ this.scrollOffset = 0;
12866
+ /** @type {boolean} Whether the scroller is oriented horizontally */
12867
+ this.horizontal = this.$attrs.hasOwnProperty('mdOrientHorizontal');
12868
+ /** @type {!VirtualRepeatController} The repeater inside of this container */
12869
+ this.repeater = null;
12870
+ /** @type {boolean} Whether auto-shrink is enabled */
12871
+ this.autoShrink = this.$attrs.hasOwnProperty('mdAutoShrink');
12872
+ /** @type {number} Minimum number of items to auto-shrink to */
12873
+ this.autoShrinkMin = parseInt(this.$attrs.mdAutoShrinkMin, 10) || 0;
12874
+ /** @type {?number} Original container size when shrank */
12875
+ this.originalSize = null;
12876
+
12877
+ this.scroller = $element[0].getElementsByClassName('md-virtual-repeat-scroller')[0];
12878
+ this.sizer = this.scroller.getElementsByClassName('md-virtual-repeat-sizer')[0];
12879
+ this.offsetter = this.scroller.getElementsByClassName('md-virtual-repeat-offsetter')[0];
12880
+
12881
+ $$rAF(angular.bind(this, this.updateSize));
12882
+
12883
+ // TODO: Come up with a more robust (But hopefully also quick!) way of
12884
+ // detecting that we're not visible.
12885
+ if ($attrs.ngHide) {
12886
+ $scope.$watch($attrs.ngHide, angular.bind(this, function(hidden) {
12887
+ if (!hidden) {
12888
+ $$rAF(angular.bind(this, this.updateSize));
12889
+ }
12890
+ }));
12891
+ }
12892
+ }
12893
+ VirtualRepeatContainerController.$inject = ["$$rAF", "$scope", "$element", "$attrs"];
12894
+
12895
+
12896
+ /** Called by the md-virtual-repeat inside of the container at startup. */
12897
+ VirtualRepeatContainerController.prototype.register = function(repeaterCtrl) {
12898
+ this.repeater = repeaterCtrl;
12899
+
12900
+ angular.element(this.scroller)
12901
+ .on('scroll wheel touchmove touchend', angular.bind(this, this.handleScroll_));
12902
+ };
12903
+
12904
+
12905
+ /** @return {boolean} Whether the container is configured for horizontal scrolling. */
12906
+ VirtualRepeatContainerController.prototype.isHorizontal = function() {
12907
+ return this.horizontal;
12908
+ };
12909
+
12910
+
12911
+ /** @return {number} The size (width or height) of the container. */
12912
+ VirtualRepeatContainerController.prototype.getSize = function() {
12913
+ return this.size;
12914
+ };
12915
+
12916
+
12917
+ /**
12918
+ * Resizes the container.
12919
+ * @private
12920
+ * @param {number} The new size to set.
12921
+ */
12922
+ VirtualRepeatContainerController.prototype.setSize_ = function(size) {
12923
+ this.size = size;
12924
+ this.$element[0].style[this.isHorizontal() ? 'width' : 'height'] = size + 'px';
12925
+ };
12926
+
12927
+
12928
+ /** Instructs the container to re-measure its size. */
12929
+ VirtualRepeatContainerController.prototype.updateSize = function() {
12930
+ if (this.originalSize) return;
12931
+
12932
+ this.size = this.isHorizontal()
12933
+ ? this.$element[0].clientWidth
12934
+ : this.$element[0].clientHeight;
12935
+ this.repeater && this.repeater.containerUpdated();
12936
+ };
12937
+
12938
+
12939
+ /** @return {number} The container's scrollHeight or scrollWidth. */
12940
+ VirtualRepeatContainerController.prototype.getScrollSize = function() {
12941
+ return this.scrollSize;
12942
+ };
12943
+
12944
+
12945
+ /**
12946
+ * Sets the scroller element to the specified size.
12947
+ * @private
12948
+ * @param {number} size The new size.
12949
+ */
12950
+ VirtualRepeatContainerController.prototype.sizeScroller_ = function(size) {
12951
+ var dimension = this.isHorizontal() ? 'width' : 'height';
12952
+ var crossDimension = this.isHorizontal() ? 'height' : 'width';
12953
+
12954
+ // If the size falls within the browser's maximum explicit size for a single element, we can
12955
+ // set the size and be done. Otherwise, we have to create children that add up the the desired
12956
+ // size.
12957
+ if (size < MAX_ELEMENT_SIZE) {
12958
+ this.sizer.style[dimension] = size + 'px';
12959
+ } else {
12960
+ // Clear any existing dimensions.
12961
+ this.sizer.innerHTML = '';
12962
+ this.sizer.style[dimension] = 'auto';
12963
+ this.sizer.style[crossDimension] = 'auto';
12964
+
12965
+ // Divide the total size we have to render into N max-size pieces.
12966
+ var numChildren = Math.floor(size / MAX_ELEMENT_SIZE);
12967
+
12968
+ // Element template to clone for each max-size piece.
12969
+ var sizerChild = document.createElement('div');
12970
+ sizerChild.style[dimension] = MAX_ELEMENT_SIZE + 'px';
12971
+ sizerChild.style[crossDimension] = '1px';
12972
+
12973
+ for (var i = 0; i < numChildren; i++) {
12974
+ this.sizer.appendChild(sizerChild.cloneNode(false));
12975
+ }
12976
+
12977
+ // Re-use the element template for the remainder.
12978
+ sizerChild.style[dimension] = (size - (numChildren * MAX_ELEMENT_SIZE)) + 'px';
12979
+ this.sizer.appendChild(sizerChild);
12980
+ }
12981
+ };
12982
+
12983
+
12984
+ /**
12985
+ * If auto-shrinking is enabled, shrinks or unshrinks as appropriate.
12986
+ * @private
12987
+ * @param {number} size The new size.
12988
+ */
12989
+ VirtualRepeatContainerController.prototype.autoShrink_ = function(size) {
12990
+ var shrinkSize = Math.max(size, this.autoShrinkMin * this.repeater.getItemSize());
12991
+ if (this.autoShrink && shrinkSize !== this.size) {
12992
+ if (shrinkSize < (this.originalSize || this.size)) {
12993
+ if (!this.originalSize) {
12994
+ this.originalSize = this.size;
12995
+ }
12996
+
12997
+ this.setSize_(shrinkSize);
12998
+ } else if (this.originalSize) {
12999
+ this.setSize_(this.originalSize);
13000
+ this.originalSize = null;
13001
+ }
13002
+ }
13003
+ };
13004
+
13005
+
13006
+ /**
13007
+ * Sets the scrollHeight or scrollWidth. Called by the repeater based on
13008
+ * its item count and item size.
13009
+ * @param {number} size The new size.
13010
+ */
13011
+ VirtualRepeatContainerController.prototype.setScrollSize = function(size) {
13012
+ if (this.scrollSize === size) return;
13013
+
13014
+ this.sizeScroller_(size);
13015
+ this.autoShrink_(size);
13016
+ this.scrollSize = size;
13017
+ };
13018
+
13019
+
13020
+ /** @return {number} The container's current scroll offset. */
13021
+ VirtualRepeatContainerController.prototype.getScrollOffset = function() {
13022
+ return this.scrollOffset;
13023
+ };
13024
+
13025
+ /**
13026
+ * Scrolls to a given scrollTop position.
13027
+ * @param {number} position
13028
+ */
13029
+ VirtualRepeatContainerController.prototype.scrollTo = function(position) {
13030
+ this.scroller[this.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = position;
13031
+ this.handleScroll_();
13032
+ };
13033
+
13034
+ VirtualRepeatContainerController.prototype.resetScroll = function() {
13035
+ this.scrollTo(0);
13036
+ };
13037
+
13038
+
13039
+ VirtualRepeatContainerController.prototype.handleScroll_ = function() {
13040
+ var offset = this.isHorizontal() ? this.scroller.scrollLeft : this.scroller.scrollTop;
13041
+ if (offset === this.scrollOffset) return;
13042
+
13043
+ var itemSize = this.repeater.getItemSize();
13044
+ if (!itemSize) return;
13045
+
13046
+ var numItems = Math.max(0, Math.floor(offset / itemSize) - NUM_EXTRA);
13047
+
13048
+ var transform = this.isHorizontal() ? 'translateX(' : 'translateY(';
13049
+ transform += (numItems * itemSize) + 'px)';
13050
+
13051
+ this.scrollOffset = offset;
13052
+ this.offsetter.style.webkitTransform = transform;
13053
+ this.offsetter.style.transform = transform;
13054
+
13055
+ this.repeater.containerUpdated();
13056
+ };
13057
+
13058
+
13059
+ /**
13060
+ * @ngdoc directive
13061
+ * @name mdVirtualRepeat
13062
+ * @module material.components.virtualRepeat
13063
+ * @restrict A
13064
+ * @priority 1000
13065
+ * @description
13066
+ * `md-virtual-repeat` specifies an element to repeat using virtual scrolling.
13067
+ *
13068
+ * Virtual repeat is a limited substitute for ng-repeat that renders only
13069
+ * enough dom nodes to fill the container and recycling them as the user scrolls.
13070
+ * Arrays, but not objects are supported for iteration.
13071
+ * Track by, as alias, and (key, value) syntax are not supported.
13072
+ *
13073
+ * @usage
13074
+ * <hljs lang="html">
13075
+ * <md-virtual-repeat-container>
13076
+ * <div md-virtual-repeat="i in items">Hello {{i}}!</div>
13077
+ * </md-virtual-repeat-container>
13078
+ *
13079
+ * <md-virtual-repeat-container md-orient-horizontal>
13080
+ * <div md-virtual-repeat="i in items" md-item-size="20">Hello {{i}}!</div>
13081
+ * </md-virtual-repeat-container>
13082
+ * </hljs>
13083
+ *
13084
+ * @param {number=} md-item-size The height or width of the repeated elements (which
13085
+ * must be identical for each element). Optional. Will attempt to read the size
13086
+ * from the dom if missing, but still assumes that all repeated nodes have same
13087
+ * height or width.
13088
+ * @param {string=} md-extra-name Evaluates to an additional name to which
13089
+ * the current iterated item can be assigned on the repeated scope. (Needed
13090
+ * for use in md-autocomplete).
13091
+ */
13092
+ function VirtualRepeatDirective($parse) {
13093
+ return {
13094
+ controller: VirtualRepeatController,
13095
+ priority: 1000,
13096
+ require: ['mdVirtualRepeat', '^^mdVirtualRepeatContainer'],
13097
+ restrict: 'A',
13098
+ terminal: true,
13099
+ transclude: 'element',
13100
+ compile: function VirtualRepeatCompile($element, $attrs) {
13101
+ var expression = $attrs.mdVirtualRepeat;
13102
+ var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)\s*$/);
13103
+ var repeatName = match[1];
13104
+ var repeatListExpression = $parse(match[2]);
13105
+ var extraName = $attrs.mdExtraName && $parse($attrs.mdExtraName);
13106
+
13107
+ return function VirtualRepeatLink($scope, $element, $attrs, ctrl, $transclude) {
13108
+ ctrl[0].link_(ctrl[1], $transclude, repeatName, repeatListExpression, extraName);
13109
+ };
13110
+ }
13111
+ };
13112
+ }
13113
+ VirtualRepeatDirective.$inject = ["$parse"];
13114
+
13115
+
13116
+ /** @ngInject */
13117
+ function VirtualRepeatController($scope, $element, $attrs, $browser, $document, $$rAF) {
13118
+ this.$scope = $scope;
13119
+ this.$element = $element;
13120
+ this.$attrs = $attrs;
13121
+ this.$browser = $browser;
13122
+ this.$document = $document;
13123
+ this.$$rAF = $$rAF;
13124
+
13125
+ /** @type {!Function} Backup reference to $browser.$$checkUrlChange */
13126
+ this.browserCheckUrlChange = $browser.$$checkUrlChange;
13127
+ /** @type {number} Most recent starting repeat index (based on scroll offset) */
13128
+ this.newStartIndex = 0;
13129
+ /** @type {number} Most recent ending repeat index (based on scroll offset) */
13130
+ this.newEndIndex = 0;
13131
+ /** @type {number} Previous starting repeat index (based on scroll offset) */
13132
+ this.startIndex = 0;
13133
+ /** @type {number} Previous ending repeat index (based on scroll offset) */
13134
+ this.endIndex = 0;
13135
+ // TODO: measure width/height of first element from dom if not provided.
13136
+ // getComputedStyle?
13137
+ /** @type {?number} Height/width of repeated elements. */
13138
+ this.itemSize = $scope.$eval($attrs.mdItemSize) || null;
13139
+
13140
+ /** @type {boolean} Whether this is the first time that items are rendered. */
13141
+ this.isFirstRender = true;
13142
+
13143
+ /** @type {number} Most recently seen length of items. */
13144
+ this.itemsLength = 0;
13145
+
13146
+ /**
13147
+ * Presently rendered blocks by repeat index.
13148
+ * @type {Object<number, !VirtualRepeatController.Block}
13149
+ */
13150
+ this.blocks = {};
13151
+ /** @type {Array<!VirtualRepeatController.Block>} A pool of presently unused blocks. */
13152
+ this.pooledBlocks = [];
13153
+ }
13154
+ VirtualRepeatController.$inject = ["$scope", "$element", "$attrs", "$browser", "$document", "$$rAF"];
13155
+
13156
+
13157
+ /**
13158
+ * An object representing a repeated item.
13159
+ * @typedef {{element: !jqLite, new: boolean, scope: !angular.Scope}}
13160
+ */
13161
+ VirtualRepeatController.Block;
13162
+
13163
+
13164
+ /**
13165
+ * Called at startup by the md-virtual-repeat postLink function.
13166
+ * @param {!VirtualRepeatContainerController} container The container's controller.
13167
+ * @param {!Function} transclude The repeated element's bound transclude function.
13168
+ * @param {string} repeatName The left hand side of the repeat expression, indicating
13169
+ * the name for each item in the array.
13170
+ * @param {!Function} repeatListExpression A compiled expression based on the right hand side
13171
+ * of the repeat expression. Points to the array to repeat over.
13172
+ * @param {string|undefined} extraName The optional extra repeatName.
13173
+ */
13174
+ VirtualRepeatController.prototype.link_ =
13175
+ function(container, transclude, repeatName, repeatListExpression, extraName) {
13176
+ this.container = container;
13177
+ this.transclude = transclude;
13178
+ this.repeatName = repeatName;
13179
+ this.repeatListExpression = repeatListExpression;
13180
+ this.extraName = extraName;
13181
+ this.sized = false;
13182
+
13183
+ this.container.register(this);
13184
+ };
13185
+
13186
+
13187
+ /** @private Attempts to set itemSize by measuring a repeated element in the dom */
13188
+ VirtualRepeatController.prototype.readItemSize_ = function() {
13189
+ this.items = this.repeatListExpression(this.$scope);
13190
+ this.parentNode = this.$element[0].parentNode;
13191
+ var block = this.getBlock_(0);
13192
+
13193
+ this.itemSize = block.element[0][
13194
+ this.container.isHorizontal() ? 'offsetWidth' : 'offsetHeight'] || null;
13195
+
13196
+ this.blocks[0] = block;
13197
+ this.poolBlock_(0);
13198
+
13199
+ if (this.itemSize) {
13200
+ this.containerUpdated();
13201
+ }
13202
+ };
13203
+
13204
+
13205
+ /**
13206
+ * Called by the container. Informs us that the containers scroll or size has
13207
+ * changed.
13208
+ */
13209
+ VirtualRepeatController.prototype.containerUpdated = function() {
13210
+ // If itemSize is unknown, attempt to measure it.
13211
+ if (!this.itemSize) {
13212
+ this.$$rAF(angular.bind(this, this.readItemSize_));
13213
+
13214
+ return;
13215
+ } else if (!this.sized) {
13216
+ this.items = this.repeatListExpression(this.$scope);
13217
+ }
13218
+
13219
+ if (!this.sized) {
13220
+ this.sized = true;
13221
+ this.$scope.$watchCollection(this.repeatListExpression,
13222
+ angular.bind(this, this.virtualRepeatUpdate_));
13223
+ }
13224
+
13225
+ this.updateIndexes_();
13226
+
13227
+ if (this.newStartIndex !== this.startIndex ||
13228
+ this.newEndIndex !== this.endIndex ||
13229
+ this.container.getScrollOffset() > this.container.getScrollSize()) {
13230
+ this.virtualRepeatUpdate_(this.items, this.items);
13231
+ }
13232
+ };
13233
+
13234
+
13235
+ /**
13236
+ * Called by the container. Returns the size of a single repeated item.
13237
+ * @return {?number} Size of a repeated item.
13238
+ */
13239
+ VirtualRepeatController.prototype.getItemSize = function() {
13240
+ return this.itemSize;
13241
+ };
13242
+
13243
+
13244
+ /**
13245
+ * Updates the order and visible offset of repeated blocks in response to scrolling
13246
+ * or items updates.
13247
+ * @private
13248
+ */
13249
+ VirtualRepeatController.prototype.virtualRepeatUpdate_ = function(items, oldItems) {
13250
+ var itemsLength = items ? items.length : 0;
13251
+ var lengthChanged = false;
13252
+
13253
+ if (itemsLength !== this.itemsLength) {
13254
+ lengthChanged = true;
13255
+ this.itemsLength = itemsLength;
13256
+ }
13257
+
13258
+ // If the number of items shrank, scroll up to the top.
13259
+ if (this.items && itemsLength < this.items.length && this.container.getScrollOffset() !== 0) {
13260
+ this.items = items;
13261
+ this.container.resetScroll();
13262
+ return;
13263
+ }
13264
+
13265
+ this.items = items;
13266
+ if (items !== oldItems) {
13267
+ this.updateIndexes_();
13268
+ }
13269
+
13270
+ this.parentNode = this.$element[0].parentNode;
12246
13271
 
12247
- function init () {
12248
- setDefaults();
12249
- manipulateElement();
12250
- bindEvents();
12251
- configureWatchers();
12252
- addAriaLabel();
12253
- }
13272
+ if (lengthChanged) {
13273
+ this.container.setScrollSize(itemsLength * this.itemSize);
13274
+ }
12254
13275
 
12255
- function setDefaults () {
12256
- if (!angular.isDefined(attr.mdDelay)) scope.delay = TOOLTIP_SHOW_DELAY;
12257
- }
13276
+ if (this.isFirstRender) {
13277
+ this.isFirstRender = false;
13278
+ var startIndex = this.$attrs.mdStartIndex ? this.$scope.$eval(this.$attrs.mdStartIndex) : 0;
13279
+ this.container.scrollTo(startIndex * this.itemSize);
13280
+ }
12258
13281
 
12259
- function configureWatchers () {
12260
- scope.$on('$destroy', function() {
12261
- scope.visible = false;
12262
- element.remove();
12263
- angular.element($window).off('resize', debouncedOnResize);
12264
- });
12265
- scope.$watch('visible', function (isVisible) {
12266
- if (isVisible) showTooltip();
12267
- else hideTooltip();
12268
- });
12269
- }
13282
+ // Detach and pool any blocks that are no longer in the viewport.
13283
+ Object.keys(this.blocks).forEach(function(blockIndex) {
13284
+ var index = parseInt(blockIndex, 10);
13285
+ if (index < this.newStartIndex || index >= this.newEndIndex) {
13286
+ this.poolBlock_(index);
13287
+ }
13288
+ }, this);
13289
+
13290
+ // Add needed blocks.
13291
+ // For performance reasons, temporarily block browser url checks as we digest
13292
+ // the restored block scopes ($$checkUrlChange reads window.location to
13293
+ // check for changes and trigger route change, etc, which we don't need when
13294
+ // trying to scroll at 60fps).
13295
+ this.$browser.$$checkUrlChange = angular.noop;
13296
+
13297
+ var i, block,
13298
+ newStartBlocks = [],
13299
+ newEndBlocks = [];
13300
+
13301
+ // Collect blocks at the top.
13302
+ for (i = this.newStartIndex; i < this.newEndIndex && this.blocks[i] == null; i++) {
13303
+ block = this.getBlock_(i);
13304
+ this.updateBlock_(block, i);
13305
+ newStartBlocks.push(block);
13306
+ }
12270
13307
 
12271
- function addAriaLabel () {
12272
- if (!parent.attr('aria-label') && !parent.text().trim()) {
12273
- parent.attr('aria-label', element.text().trim());
12274
- }
12275
- }
13308
+ // Update blocks that are already rendered.
13309
+ for (; this.blocks[i] != null; i++) {
13310
+ this.updateBlock_(this.blocks[i], i);
13311
+ }
13312
+ var maxIndex = i - 1;
12276
13313
 
12277
- function manipulateElement () {
12278
- element.detach();
12279
- element.attr('role', 'tooltip');
12280
- }
13314
+ // Collect blocks at the end.
13315
+ for (; i < this.newEndIndex; i++) {
13316
+ block = this.getBlock_(i);
13317
+ this.updateBlock_(block, i);
13318
+ newEndBlocks.push(block);
13319
+ }
12281
13320
 
12282
- function getParentWithPointerEvents () {
12283
- var parent = element.parent();
12284
- while (parent && $window.getComputedStyle(parent[0])['pointer-events'] == 'none') {
12285
- parent = parent.parent();
12286
- }
12287
- return parent;
12288
- }
13321
+ // Attach collected blocks to the document.
13322
+ if (newStartBlocks.length) {
13323
+ this.parentNode.insertBefore(
13324
+ this.domFragmentFromBlocks_(newStartBlocks),
13325
+ this.$element[0].nextSibling);
13326
+ }
13327
+ if (newEndBlocks.length) {
13328
+ this.parentNode.insertBefore(
13329
+ this.domFragmentFromBlocks_(newEndBlocks),
13330
+ this.blocks[maxIndex] && this.blocks[maxIndex].element[0].nextSibling);
13331
+ }
12289
13332
 
12290
- function getNearestContentElement () {
12291
- var current = element.parent()[0];
12292
- // Look for the nearest parent md-content, stopping at the rootElement.
12293
- while (current && current !== $rootElement[0] && current !== document.body) {
12294
- current = current.parentNode;
12295
- }
12296
- return current;
12297
- }
13333
+ // Restore $$checkUrlChange.
13334
+ this.$browser.$$checkUrlChange = this.browserCheckUrlChange;
12298
13335
 
12299
- function hasComputedStyleValue(key, value) {
12300
- // Check if we should show it or not...
12301
- var computedStyles = $window.getComputedStyle(element[0]);
12302
- return angular.isDefined(computedStyles[key]) && (computedStyles[key] == value);
12303
- }
13336
+ this.startIndex = this.newStartIndex;
13337
+ this.endIndex = this.newEndIndex;
13338
+ };
12304
13339
 
12305
- function bindEvents () {
12306
- var mouseActive = false;
12307
- var enterHandler = function() {
12308
- if (!hasComputedStyleValue('pointer-events','none')) {
12309
- setVisible(true);
12310
- }
12311
- };
12312
- var leaveHandler = function () {
12313
- var autohide = scope.hasOwnProperty('autohide') ? scope.autohide : attr.hasOwnProperty('mdAutohide');
12314
- if (autohide || mouseActive || ($document[0].activeElement !== parent[0]) ) {
12315
- setVisible(false);
12316
- }
12317
- mouseActive = false;
12318
- };
12319
13340
 
12320
- // to avoid `synthetic clicks` we listen to mousedown instead of `click`
12321
- parent.on('mousedown', function() { mouseActive = true; });
12322
- parent.on('focus mouseenter touchstart', enterHandler );
12323
- parent.on('blur mouseleave touchend touchcancel', leaveHandler );
13341
+ /**
13342
+ * @param {number} index Where the block is to be in the repeated list.
13343
+ * @return {!VirtualRepeatController.Block} A new or pooled block to place at the specified index.
13344
+ * @private
13345
+ */
13346
+ VirtualRepeatController.prototype.getBlock_ = function(index) {
13347
+ if (this.pooledBlocks.length) {
13348
+ return this.pooledBlocks.pop();
13349
+ }
12324
13350
 
13351
+ var block;
13352
+ this.transclude(angular.bind(this, function(clone, scope) {
13353
+ block = {
13354
+ element: clone,
13355
+ new: true,
13356
+ scope: scope
13357
+ };
12325
13358
 
12326
- angular.element($window).on('resize', debouncedOnResize);
12327
- }
13359
+ this.updateScope_(scope, index);
13360
+ this.parentNode.appendChild(clone[0]);
13361
+ }));
12328
13362
 
12329
- function setVisible (value) {
12330
- setVisible.value = !!value;
12331
- if (!setVisible.queued) {
12332
- if (value) {
12333
- setVisible.queued = true;
12334
- $timeout(function() {
12335
- scope.visible = setVisible.value;
12336
- setVisible.queued = false;
12337
- }, scope.delay);
12338
- } else {
12339
- $timeout(function() { scope.visible = false; });
12340
- }
12341
- }
12342
- }
13363
+ return block;
13364
+ };
12343
13365
 
12344
- function showTooltip() {
12345
- // Insert the element before positioning it, so we can get the position
12346
- // and check if we should display it
12347
- tooltipParent.append(element);
12348
13366
 
12349
- // Check if we should display it or not.
12350
- // This handles hide-* and show-* along with any user defined css
12351
- if ( hasComputedStyleValue('display','none') ) {
12352
- scope.visible = false;
12353
- element.detach();
12354
- return;
12355
- }
13367
+ /**
13368
+ * Updates and if not in a digest cycle, digests the specified block's scope to the data
13369
+ * at the specified index.
13370
+ * @param {!VirtualRepeatController.Block} block The block whose scope should be updated.
13371
+ * @param {number} index The index to set.
13372
+ * @private
13373
+ */
13374
+ VirtualRepeatController.prototype.updateBlock_ = function(block, index) {
13375
+ this.blocks[index] = block;
12356
13376
 
12357
- positionTooltip();
12358
- angular.forEach([element, background, content], function (element) {
12359
- $animate.addClass(element, 'md-show');
12360
- });
12361
- }
13377
+ if (!block.new &&
13378
+ (block.scope.$index === index && block.scope[this.repeatName] === this.items[index])) {
13379
+ return;
13380
+ }
13381
+ block.new = false;
12362
13382
 
12363
- function hideTooltip() {
12364
- $q.all([
12365
- $animate.removeClass(content, 'md-show'),
12366
- $animate.removeClass(background, 'md-show'),
12367
- $animate.removeClass(element, 'md-show')
12368
- ]).then(function () {
12369
- if (!scope.visible) element.detach();
12370
- });
12371
- }
13383
+ // Update and digest the block's scope.
13384
+ this.updateScope_(block.scope, index);
12372
13385
 
12373
- function positionTooltip() {
12374
- var tipRect = $mdUtil.offsetRect(element, tooltipParent);
12375
- var parentRect = $mdUtil.offsetRect(parent, tooltipParent);
12376
- var newPosition = getPosition(direction);
13386
+ // Perform digest before reattaching the block.
13387
+ // Any resulting synchronous dom mutations should be much faster as a result.
13388
+ // This might break some directives, but I'm going to try it for now.
13389
+ if (!this.$scope.$root.$$phase) {
13390
+ block.scope.$digest();
13391
+ }
13392
+ };
12377
13393
 
12378
- // If the user provided a direction, just nudge the tooltip onto the screen
12379
- // Otherwise, recalculate based on 'top' since default is 'bottom'
12380
- if (direction) {
12381
- newPosition = fitInParent(newPosition);
12382
- } else if (newPosition.top > element.prop('offsetParent').scrollHeight - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE) {
12383
- newPosition = fitInParent(getPosition('top'));
12384
- }
12385
13394
 
12386
- element.css({top: newPosition.top + 'px', left: newPosition.left + 'px'});
13395
+ /**
13396
+ * Updates scope to the data at the specified index.
13397
+ * @param {!angular.Scope} scope The scope which should be updated.
13398
+ * @param {number} index The index to set.
13399
+ * @private
13400
+ */
13401
+ VirtualRepeatController.prototype.updateScope_ = function(scope, index) {
13402
+ scope.$index = index;
13403
+ scope[this.repeatName] = this.items && this.items[index];
13404
+ if (this.extraName) scope[this.extraName(this.$scope)] = this.items[index];
13405
+ };
12387
13406
 
12388
- positionBackground();
12389
13407
 
12390
- function positionBackground () {
12391
- var size = direction === 'left' || direction === 'right'
12392
- ? Math.sqrt(Math.pow(tipRect.width, 2) + Math.pow(tipRect.height / 2, 2)) * 2
12393
- : Math.sqrt(Math.pow(tipRect.width / 2, 2) + Math.pow(tipRect.height, 2)) * 2,
12394
- position = direction === 'left' ? { left: 100, top: 50 }
12395
- : direction === 'right' ? { left: 0, top: 50 }
12396
- : direction === 'top' ? { left: 50, top: 100 }
12397
- : { left: 50, top: 0 };
12398
- background.css({
12399
- width: size + 'px',
12400
- height: size + 'px',
12401
- left: position.left + '%',
12402
- top: position.top + '%'
12403
- });
12404
- }
13408
+ /**
13409
+ * Pools the block at the specified index (Pulls its element out of the dom and stores it).
13410
+ * @param {number} index The index at which the block to pool is stored.
13411
+ * @private
13412
+ */
13413
+ VirtualRepeatController.prototype.poolBlock_ = function(index) {
13414
+ this.pooledBlocks.push(this.blocks[index]);
13415
+ this.parentNode.removeChild(this.blocks[index].element[0]);
13416
+ delete this.blocks[index];
13417
+ };
12405
13418
 
12406
- function fitInParent (pos) {
12407
- var newPosition = { left: pos.left, top: pos.top };
12408
- newPosition.left = Math.min( newPosition.left, tooltipParent.prop('scrollWidth') - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE );
12409
- newPosition.left = Math.max( newPosition.left, TOOLTIP_WINDOW_EDGE_SPACE );
12410
- newPosition.top = Math.min( newPosition.top, tooltipParent.prop('scrollHeight') - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE );
12411
- newPosition.top = Math.max( newPosition.top, TOOLTIP_WINDOW_EDGE_SPACE );
12412
- return newPosition;
12413
- }
12414
13419
 
12415
- function getPosition (dir) {
12416
- return dir === 'left'
12417
- ? { left: parentRect.left - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE,
12418
- top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
12419
- : dir === 'right'
12420
- ? { left: parentRect.left + parentRect.width + TOOLTIP_WINDOW_EDGE_SPACE,
12421
- top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
12422
- : dir === 'top'
12423
- ? { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
12424
- top: parentRect.top - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE }
12425
- : { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
12426
- top: parentRect.top + parentRect.height + TOOLTIP_WINDOW_EDGE_SPACE };
12427
- }
12428
- }
13420
+ /**
13421
+ * Produces a dom fragment containing the elements from the list of blocks.
13422
+ * @param {!Array<!VirtualRepeatController.Block>} blocks The blocks whose elements
13423
+ * should be added to the document fragment.
13424
+ * @return {DocumentFragment}
13425
+ * @private
13426
+ */
13427
+ VirtualRepeatController.prototype.domFragmentFromBlocks_ = function(blocks) {
13428
+ var fragment = this.$document[0].createDocumentFragment();
13429
+ blocks.forEach(function(block) {
13430
+ fragment.appendChild(block.element[0]);
13431
+ });
13432
+ return fragment;
13433
+ };
12429
13434
 
12430
- }
12431
13435
 
12432
- }
12433
- MdTooltipDirective.$inject = ["$timeout", "$window", "$$rAF", "$document", "$mdUtil", "$mdTheming", "$rootElement", "$animate", "$q"];
13436
+ /**
13437
+ * Updates start and end indexes based on length of repeated items and container size.
13438
+ * @private
13439
+ */
13440
+ VirtualRepeatController.prototype.updateIndexes_ = function() {
13441
+ var itemsLength = this.items ? this.items.length : 0;
13442
+ var containerLength = Math.ceil(this.container.getSize() / this.itemSize);
13443
+
13444
+ this.newStartIndex = Math.max(0, Math.min(
13445
+ itemsLength - containerLength,
13446
+ Math.floor(this.container.getScrollOffset() / this.itemSize)));
13447
+ this.newEndIndex = Math.min(itemsLength, this.newStartIndex + containerLength + NUM_EXTRA);
13448
+ this.newStartIndex = Math.max(0, this.newStartIndex - NUM_EXTRA);
13449
+ };
12434
13450
 
12435
13451
  })();
12436
13452
  (function(){
@@ -12455,7 +13471,7 @@ var ITEM_HEIGHT = 41,
12455
13471
  MENU_PADDING = 8;
12456
13472
 
12457
13473
  function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $mdTheming, $window,
12458
- $animate, $rootElement, $attrs) {
13474
+ $animate, $rootElement, $attrs, $q) {
12459
13475
  //-- private variables
12460
13476
  var ctrl = this,
12461
13477
  itemParts = $scope.itemsExpr.split(/ in /i),
@@ -12646,11 +13662,13 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12646
13662
  * @param oldHidden
12647
13663
  */
12648
13664
  function handleHiddenChange (hidden, oldHidden) {
12649
- if (!hidden && oldHidden) positionDropdown();
12650
- if (!hidden) {
13665
+ if (!hidden && oldHidden) {
13666
+ positionDropdown();
12651
13667
  if (elements) $timeout(function () { $mdUtil.disableScrollAround(elements.ul); }, 0, false);
12652
- } else {
12653
- $mdUtil.enableScrolling();
13668
+ } else if (hidden && !oldHidden) {
13669
+ $timeout(function() {
13670
+ $mdUtil.enableScrolling();
13671
+ }, 0, false);
12654
13672
  }
12655
13673
  }
12656
13674
 
@@ -12683,10 +13701,23 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12683
13701
  */
12684
13702
  function selectedItemChange (selectedItem, previousSelectedItem) {
12685
13703
  if (selectedItem) {
12686
- $scope.searchText = getDisplayValue(selectedItem);
13704
+ getDisplayValue(selectedItem).then(function(val) {
13705
+ $scope.searchText = val;
13706
+ });
12687
13707
  }
12688
- if ($scope.itemChange && selectedItem !== previousSelectedItem)
12689
- $scope.itemChange(getItemScope(selectedItem));
13708
+
13709
+ if (selectedItem !== previousSelectedItem) announceItemChange(selectedItem);
13710
+ }
13711
+
13712
+ /**
13713
+ * Use the user-defined expression to announce changes each time a new item is selected
13714
+ */
13715
+ function announceItemChange( current ) {
13716
+ angular.isFunction($scope.itemChange) && $scope.itemChange( getItemAsNameVal(current) );
13717
+ }
13718
+
13719
+ function announceTextChange( value ) {
13720
+ angular.isFunction($scope.textChange) && $scope.textChange(value);
12690
13721
  }
12691
13722
 
12692
13723
  /**
@@ -12729,23 +13760,30 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12729
13760
  */
12730
13761
  function handleSearchText (searchText, previousSearchText) {
12731
13762
  ctrl.index = getDefaultIndex();
12732
- //-- do nothing on init
13763
+ // do nothing on init
12733
13764
  if (searchText === previousSearchText) return;
12734
- //-- clear selected item if search text no longer matches it
12735
- if (searchText !== getDisplayValue($scope.selectedItem)) $scope.selectedItem = null;
12736
- else return;
12737
- //-- trigger change event if available
12738
- if ($scope.textChange && searchText !== previousSearchText)
12739
- $scope.textChange(getItemScope($scope.selectedItem));
12740
- //-- cancel results if search text is not long enough
12741
- if (!isMinLengthMet()) {
12742
- ctrl.loading = false;
12743
- ctrl.matches = [];
12744
- ctrl.hidden = shouldHide();
12745
- updateMessages();
12746
- } else {
12747
- handleQuery();
12748
- }
13765
+
13766
+ getDisplayValue($scope.selectedItem).then(function(val) {
13767
+ // clear selected item if search text no longer matches it
13768
+ if (searchText !== val)
13769
+ {
13770
+ $scope.selectedItem = null;
13771
+
13772
+ // trigger change event if available
13773
+ if ( searchText !== previousSearchText ) announceTextChange(searchText);
13774
+
13775
+ // cancel results if search text is not long enough
13776
+ if (!isMinLengthMet()) {
13777
+ ctrl.loading = false;
13778
+ ctrl.matches = [];
13779
+ ctrl.hidden = shouldHide();
13780
+ updateMessages();
13781
+ } else {
13782
+ handleQuery();
13783
+ }
13784
+ }
13785
+ });
13786
+
12749
13787
  }
12750
13788
 
12751
13789
  /**
@@ -12819,7 +13857,15 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12819
13857
  * @returns {*}
12820
13858
  */
12821
13859
  function getDisplayValue (item) {
12822
- return (item && $scope.itemText) ? $scope.itemText(getItemScope(item)) : item;
13860
+ return $q.when( getItemText(item) || item );
13861
+
13862
+ /**
13863
+ * Getter function to invoke user-defined expression (in the directive)
13864
+ * to convert your object to a single string.
13865
+ */
13866
+ function getItemText(item) {
13867
+ return (item && $scope.itemText) ? $scope.itemText(getItemAsNameVal(item)) : null;
13868
+ }
12823
13869
  }
12824
13870
 
12825
13871
  /**
@@ -12827,13 +13873,18 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12827
13873
  * @param item
12828
13874
  * @returns {{}}
12829
13875
  */
12830
- function getItemScope (item) {
12831
- if (!item) return;
13876
+ function getItemAsNameVal (item) {
13877
+ if (!item) return undefined;
13878
+
12832
13879
  var locals = {};
12833
13880
  if (ctrl.itemName) locals[ctrl.itemName] = item;
13881
+
12834
13882
  return locals;
12835
13883
  }
12836
13884
 
13885
+
13886
+
13887
+
12837
13888
  /**
12838
13889
  * Returns the default index based on whether or not autoselect is enabled.
12839
13890
  * @returns {number}
@@ -12855,7 +13906,7 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12855
13906
  * @returns {*}
12856
13907
  */
12857
13908
  function getCurrentDisplayValue () {
12858
- return getDisplayValue(ctrl.matches[ctrl.index]);
13909
+ return getDisplayValue( ctrl.matches[ctrl.index] );
12859
13910
  }
12860
13911
 
12861
13912
  /**
@@ -12889,19 +13940,24 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12889
13940
  * Selects the item at the given index.
12890
13941
  * @param index
12891
13942
  */
12892
- function select (index) {
12893
- $scope.selectedItem = ctrl.matches[index];
12894
- ctrl.hidden = true;
12895
- ctrl.index = 0;
12896
- ctrl.matches = [];
13943
+ function select(index) {
12897
13944
  //-- force form to update state for validation
12898
- $timeout(function () {
12899
- elements.$.input.controller('ngModel').$setViewValue(getDisplayValue($scope.selectedItem) ||
12900
- $scope.searchText);
12901
- ctrl.hidden = true;
13945
+ $timeout(function() {
13946
+ getDisplayValue(ctrl.matches[index]).then(function(val) {
13947
+ var ngModel = elements.$.input.controller('ngModel');
13948
+ ngModel.$setViewValue(val);
13949
+ ngModel.$render();
13950
+ }).finally(function() {
13951
+ $scope.selectedItem = ctrl.matches[index];
13952
+ ctrl.loading = false;
13953
+ ctrl.hidden = true;
13954
+ ctrl.index = 0;
13955
+ ctrl.matches = [];
13956
+ });
12902
13957
  });
12903
13958
  }
12904
13959
 
13960
+
12905
13961
  /**
12906
13962
  * Clears the searchText value and selected item.
12907
13963
  */
@@ -12948,7 +14004,9 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
12948
14004
  * Updates the ARIA messages
12949
14005
  */
12950
14006
  function updateMessages () {
12951
- ctrl.messages = [ getCountMessage(), getCurrentDisplayValue() ];
14007
+ getCurrentDisplayValue().then(function(msg) {
14008
+ ctrl.messages = [ getCountMessage(), msg ];
14009
+ });
12952
14010
  }
12953
14011
 
12954
14012
  /**
@@ -13004,7 +14062,7 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $
13004
14062
  }
13005
14063
 
13006
14064
  }
13007
- MdAutocompleteCtrl.$inject = ["$scope", "$element", "$mdUtil", "$mdConstant", "$timeout", "$mdTheming", "$window", "$animate", "$rootElement", "$attrs"];
14065
+ MdAutocompleteCtrl.$inject = ["$scope", "$element", "$mdUtil", "$mdConstant", "$timeout", "$mdTheming", "$window", "$animate", "$rootElement", "$attrs", "$q"];
13008
14066
 
13009
14067
  })();
13010
14068
  (function(){
@@ -13144,11 +14202,11 @@ function MdAutocomplete ($mdTheming, $mdUtil) {
13144
14202
  return '\
13145
14203
  <md-autocomplete-wrap\
13146
14204
  layout="row"\
13147
- ng-class="{ \'md-whiteframe-z1\': !floatingLabel }"\
14205
+ ng-class="{ \'md-whiteframe-z1\': !floatingLabel, \'md-menu-showing\': !$mdAutocompleteCtrl.hidden }"\
13148
14206
  role="listbox">\
13149
14207
  ' + getInputElement() + '\
13150
14208
  <md-progress-linear\
13151
- ng-if="$mdAutocompleteCtrl.loading"\
14209
+ ng-if="$mdAutocompleteCtrl.loading && !$mdAutocompleteCtrl.hidden"\
13152
14210
  md-mode="indeterminate"></md-progress-linear>\
13153
14211
  <ul role="presentation"\
13154
14212
  class="md-autocomplete-suggestions md-whiteframe-z1 {{menuClass || \'\'}}"\
@@ -13170,7 +14228,7 @@ function MdAutocomplete ($mdTheming, $mdUtil) {
13170
14228
  class="md-visually-hidden"\
13171
14229
  role="status"\
13172
14230
  aria-live="assertive">\
13173
- <p ng-repeat="message in $mdAutocompleteCtrl.messages" ng-if="message">{{message}}</p>\
14231
+ <p ng-repeat="message in $mdAutocompleteCtrl.messages track by $index" ng-if="message">{{message}}</p>\
13174
14232
  </aria-status>';
13175
14233
 
13176
14234
  function getItemTemplate() {
@@ -13201,7 +14259,7 @@ function MdAutocomplete ($mdTheming, $mdUtil) {
13201
14259
  id="fl-input-{{$mdAutocompleteCtrl.id}}"\
13202
14260
  name="{{inputName}}"\
13203
14261
  autocomplete="off"\
13204
- ng-required="isRequired"\
14262
+ ng-required="$mdAutocompleteCtrl.isRequired"\
13205
14263
  ng-minlength="inputMinlength"\
13206
14264
  ng-maxlength="inputMaxlength"\
13207
14265
  ng-disabled="$mdAutocompleteCtrl.isDisabled"\
@@ -13224,7 +14282,7 @@ function MdAutocomplete ($mdTheming, $mdUtil) {
13224
14282
  name="{{inputName}}"\
13225
14283
  ng-if="!floatingLabel"\
13226
14284
  autocomplete="off"\
13227
- ng-required="isRequired"\
14285
+ ng-required="$mdAutocompleteCtrl.isRequired"\
13228
14286
  ng-disabled="$mdAutocompleteCtrl.isDisabled"\
13229
14287
  ng-model="$mdAutocompleteCtrl.scope.searchText"\
13230
14288
  ng-keydown="$mdAutocompleteCtrl.keydown($event)"\
@@ -14559,11 +15617,23 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14559
15617
  destroyed = false,
14560
15618
  loaded = false;
14561
15619
 
15620
+ //-- define one-way bindings
15621
+ defineOneWayBinding('stretchTabs', handleStretchTabs);
15622
+
14562
15623
  //-- define public properties with change handlers
14563
- defineProperty('focusIndex', handleFocusIndexChange, $scope.selectedIndex || 0);
15624
+ defineProperty('focusIndex', handleFocusIndexChange, ctrl.selectedIndex || 0);
14564
15625
  defineProperty('offsetLeft', handleOffsetChange, 0);
14565
15626
  defineProperty('hasContent', handleHasContent, false);
14566
15627
 
15628
+ //-- define boolean attributes
15629
+ defineBooleanAttribute('noInkBar', handleInkBar);
15630
+ defineBooleanAttribute('dynamicHeight', handleDynamicHeight);
15631
+ defineBooleanAttribute('noPagination');
15632
+ defineBooleanAttribute('swipeContent');
15633
+ defineBooleanAttribute('noDisconnect');
15634
+ defineBooleanAttribute('autoselect');
15635
+ defineBooleanAttribute('centerTabs');
15636
+
14567
15637
  //-- define public properties
14568
15638
  ctrl.scope = $scope;
14569
15639
  ctrl.parent = $scope.$parent;
@@ -14575,9 +15645,9 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14575
15645
  ctrl.shouldCenterTabs = shouldCenterTabs();
14576
15646
 
14577
15647
  //-- define public methods
15648
+ ctrl.updatePagination = $mdUtil.debounce(updatePagination, 100);
14578
15649
  ctrl.redirectFocus = redirectFocus;
14579
15650
  ctrl.attachRipple = attachRipple;
14580
- ctrl.shouldStretchTabs = shouldStretchTabs;
14581
15651
  ctrl.insertTab = insertTab;
14582
15652
  ctrl.removeTab = removeTab;
14583
15653
  ctrl.select = select;
@@ -14598,7 +15668,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14598
15668
  * Perform initialization for the controller, setup events and watcher(s)
14599
15669
  */
14600
15670
  function init () {
14601
- $scope.selectedIndex = $scope.selectedIndex || 0;
15671
+ ctrl.selectedIndex = ctrl.selectedIndex || 0;
14602
15672
  compileTemplate();
14603
15673
  configureWatchers();
14604
15674
  bindEvents();
@@ -14607,11 +15677,16 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14607
15677
  updateHeightFromContent();
14608
15678
  adjustOffset();
14609
15679
  updatePagination();
14610
- ctrl.tabs[$scope.selectedIndex] && ctrl.tabs[$scope.selectedIndex].scope.select();
15680
+ updateInkBarStyles();
15681
+ ctrl.tabs[ctrl.selectedIndex] && ctrl.tabs[ctrl.selectedIndex].scope.select();
14611
15682
  loaded = true;
14612
15683
  });
14613
15684
  }
14614
15685
 
15686
+ /**
15687
+ * Compiles the template provided by the user. This is passed as an attribute from the tabs
15688
+ * directive's template function.
15689
+ */
14615
15690
  function compileTemplate () {
14616
15691
  var template = $attrs.$mdTabsTemplate,
14617
15692
  element = angular.element(elements.data);
@@ -14620,21 +15695,34 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14620
15695
  delete $attrs.$mdTabsTemplate;
14621
15696
  }
14622
15697
 
15698
+ /**
15699
+ * Binds events used by the tabs component.
15700
+ */
14623
15701
  function bindEvents () {
14624
15702
  angular.element($window).on('resize', handleWindowResize);
14625
- angular.element(elements.paging).on('DOMSubtreeModified', ctrl.updateInkBarStyles);
14626
- angular.element(elements.paging).on('DOMSubtreeModified', updatePagination);
15703
+ $scope.$on('$destroy', cleanup);
14627
15704
  }
14628
15705
 
14629
15706
  function configureWatchers () {
14630
- $mdUtil.initOptionalProperties($scope, $attrs);
14631
- $attrs.$observe('mdNoBar', function (value) { $scope.noInkBar = angular.isDefined(value); });
14632
- $scope.$watch('selectedIndex', handleSelectedIndexChange);
14633
- $scope.$watch('dynamicHeight', function (value) {
14634
- if (value) $element.addClass('md-dynamic-height');
14635
- else $element.removeClass('md-dynamic-height');
14636
- });
14637
- $scope.$on('$destroy', cleanup);
15707
+ $scope.$watch('$mdTabsCtrl.selectedIndex', handleSelectedIndexChange);
15708
+ }
15709
+
15710
+ function defineOneWayBinding (key, handler) {
15711
+ var attr = $attrs.$normalize('md-' + key);
15712
+ if (handler) defineProperty(key, handler);
15713
+ $attrs.$observe(attr, function (newValue) { ctrl[key] = newValue; });
15714
+ }
15715
+
15716
+ /**
15717
+ * Defines boolean attributes with default value set to true. (ie. md-stretch-tabs with no value
15718
+ * will be treated as being truthy)
15719
+ * @param key
15720
+ * @param handler
15721
+ */
15722
+ function defineBooleanAttribute (key, handler) {
15723
+ var attr = $attrs.$normalize('md-' + key);
15724
+ if (handler) defineProperty(key, handler);
15725
+ $attrs.$observe(attr, function (newValue) { ctrl[key] = newValue !== 'false'; });
14638
15726
  }
14639
15727
 
14640
15728
  /**
@@ -14649,6 +15737,11 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14649
15737
 
14650
15738
  //-- Change handlers
14651
15739
 
15740
+ function handleStretchTabs (stretchTabs) {
15741
+ angular.element(elements.wrapper).toggleClass('md-stretch-tabs', shouldStretchTabs());
15742
+ updateInkBarStyles();
15743
+ }
15744
+
14652
15745
  /**
14653
15746
  * Add/remove the `md-no-tab-content` class depending on `ctrl.hasContent`
14654
15747
  * @param hasContent
@@ -14687,7 +15780,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14687
15780
  function handleSelectedIndexChange (newValue, oldValue) {
14688
15781
  if (newValue === oldValue) return;
14689
15782
 
14690
- $scope.selectedIndex = getNearestSafeIndex(newValue);
15783
+ ctrl.selectedIndex = getNearestSafeIndex(newValue);
14691
15784
  ctrl.lastSelectedIndex = oldValue;
14692
15785
  ctrl.updateInkBarStyles();
14693
15786
  updateHeightFromContent();
@@ -14741,7 +15834,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14741
15834
  case $mdConstant.KEY_CODE.SPACE:
14742
15835
  case $mdConstant.KEY_CODE.ENTER:
14743
15836
  event.preventDefault();
14744
- if (!locked) $scope.selectedIndex = ctrl.focusIndex;
15837
+ if (!locked) ctrl.selectedIndex = ctrl.focusIndex;
14745
15838
  break;
14746
15839
  }
14747
15840
  ctrl.lastClick = false;
@@ -14753,7 +15846,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14753
15846
  * @param index
14754
15847
  */
14755
15848
  function select (index) {
14756
- if (!locked) ctrl.focusIndex = $scope.selectedIndex = index;
15849
+ if (!locked) ctrl.focusIndex = ctrl.selectedIndex = index;
14757
15850
  ctrl.lastClick = true;
14758
15851
  ctrl.tabs[index].element.triggerHandler('click');
14759
15852
  }
@@ -14799,26 +15892,38 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14799
15892
  */
14800
15893
  function handleWindowResize () {
14801
15894
  $scope.$apply(function () {
14802
- ctrl.lastSelectedIndex = $scope.selectedIndex;
15895
+ ctrl.lastSelectedIndex = ctrl.selectedIndex;
14803
15896
  ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);
14804
15897
  $timeout(ctrl.updateInkBarStyles, 0, false);
14805
15898
  $timeout(updatePagination);
14806
15899
  });
14807
15900
  }
14808
15901
 
15902
+ function handleInkBar (hide) {
15903
+ angular.element(elements.inkBar).toggleClass('ng-hide', hide);
15904
+ }
15905
+
15906
+ /**
15907
+ * Toggle dynamic height class when value changes
15908
+ * @param value
15909
+ */
15910
+ function handleDynamicHeight (value) {
15911
+ $element.toggleClass('md-dynamic-height', value);
15912
+ }
15913
+
14809
15914
  /**
14810
15915
  * Remove a tab from the data and select the nearest valid tab.
14811
15916
  * @param tabData
14812
15917
  */
14813
15918
  function removeTab (tabData) {
14814
- var selectedIndex = $scope.selectedIndex,
15919
+ var selectedIndex = ctrl.selectedIndex,
14815
15920
  tab = ctrl.tabs.splice(tabData.getIndex(), 1)[0];
14816
15921
  refreshIndex();
14817
15922
  //-- when removing a tab, if the selected index did not change, we have to manually trigger the
14818
15923
  // tab select/deselect events
14819
- if ($scope.selectedIndex === selectedIndex && !destroyed) {
15924
+ if (ctrl.selectedIndex === selectedIndex && !destroyed) {
14820
15925
  tab.scope.deselect();
14821
- ctrl.tabs[$scope.selectedIndex] && ctrl.tabs[$scope.selectedIndex].scope.select();
15926
+ ctrl.tabs[ctrl.selectedIndex] && ctrl.tabs[ctrl.selectedIndex].scope.select();
14822
15927
  }
14823
15928
  $timeout(function () {
14824
15929
  updatePagination();
@@ -14835,10 +15940,10 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14835
15940
  function insertTab (tabData, index) {
14836
15941
  var proto = {
14837
15942
  getIndex: function () { return ctrl.tabs.indexOf(tab); },
14838
- isActive: function () { return this.getIndex() === $scope.selectedIndex; },
14839
- isLeft: function () { return this.getIndex() < $scope.selectedIndex; },
14840
- isRight: function () { return this.getIndex() > $scope.selectedIndex; },
14841
- shouldRender: function () { return !$scope.noDisconnect || this.isActive(); },
15943
+ isActive: function () { return this.getIndex() === ctrl.selectedIndex; },
15944
+ isLeft: function () { return this.getIndex() < ctrl.selectedIndex; },
15945
+ isRight: function () { return this.getIndex() > ctrl.selectedIndex; },
15946
+ shouldRender: function () { return !ctrl.noDisconnect || this.isActive(); },
14842
15947
  hasFocus: function () { return !ctrl.lastClick
14843
15948
  && ctrl.hasFocus && this.getIndex() === ctrl.focusIndex; },
14844
15949
  id: $mdUtil.nextUid()
@@ -14852,7 +15957,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14852
15957
  processQueue();
14853
15958
  updateHasContent();
14854
15959
  //-- if autoselect is enabled, select the newly added tab
14855
- if (loaded && $scope.autoselect) $timeout(function () { select(ctrl.tabs.indexOf(tab)); });
15960
+ if (loaded && ctrl.autoselect) $timeout(function () { select(ctrl.tabs.indexOf(tab)); });
14856
15961
  $timeout(updatePagination);
14857
15962
  return tab;
14858
15963
  }
@@ -14905,7 +16010,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14905
16010
  * @returns {*}
14906
16011
  */
14907
16012
  function shouldStretchTabs () {
14908
- switch ($scope.stretchTabs) {
16013
+ switch (ctrl.stretchTabs) {
14909
16014
  case 'always': return true;
14910
16015
  case 'never': return false;
14911
16016
  default: return !ctrl.shouldPaginate
@@ -14918,7 +16023,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14918
16023
  * @returns {string|boolean}
14919
16024
  */
14920
16025
  function shouldCenterTabs () {
14921
- return $scope.centerTabs && !ctrl.shouldPaginate;
16026
+ return ctrl.centerTabs && !ctrl.shouldPaginate;
14922
16027
  }
14923
16028
 
14924
16029
  /**
@@ -14926,7 +16031,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14926
16031
  * @returns {boolean}
14927
16032
  */
14928
16033
  function shouldPaginate () {
14929
- if ($scope.noPagination || !loaded) return false;
16034
+ if (ctrl.noPagination || !loaded) return false;
14930
16035
  var canvasWidth = $element.prop('clientWidth');
14931
16036
  angular.forEach(elements.dummies, function (tab) { canvasWidth -= tab.offsetWidth; });
14932
16037
  return canvasWidth < 0;
@@ -14965,7 +16070,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14965
16070
  set: function (newValue) {
14966
16071
  var oldValue = value;
14967
16072
  value = newValue;
14968
- handler(newValue, oldValue);
16073
+ handler && handler(newValue, oldValue);
14969
16074
  }
14970
16075
  });
14971
16076
  }
@@ -14977,7 +16082,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14977
16082
  ctrl.shouldPaginate = shouldPaginate();
14978
16083
  ctrl.shouldCenterTabs = shouldCenterTabs();
14979
16084
  $timeout(function () {
14980
- adjustOffset($scope.selectedIndex);
16085
+ adjustOffset(ctrl.selectedIndex);
14981
16086
  });
14982
16087
  }
14983
16088
 
@@ -14986,12 +16091,12 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
14986
16091
  * This is triggered by `tabDirective.js` when the user's tabs have been re-ordered.
14987
16092
  */
14988
16093
  function updateTabOrder () {
14989
- var selectedItem = ctrl.tabs[$scope.selectedIndex],
16094
+ var selectedItem = ctrl.tabs[ctrl.selectedIndex],
14990
16095
  focusItem = ctrl.tabs[ctrl.focusIndex];
14991
16096
  ctrl.tabs = ctrl.tabs.sort(function (a, b) {
14992
16097
  return a.index - b.index;
14993
16098
  });
14994
- $scope.selectedIndex = ctrl.tabs.indexOf(selectedItem);
16099
+ ctrl.selectedIndex = ctrl.tabs.indexOf(selectedItem);
14995
16100
  ctrl.focusIndex = ctrl.tabs.indexOf(focusItem);
14996
16101
  }
14997
16102
 
@@ -15022,6 +16127,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
15022
16127
  * Forces the pagination to move the focused tab into view.
15023
16128
  */
15024
16129
  function adjustOffset (index) {
16130
+ if (!elements.tabs[index]) return;
15025
16131
  if (ctrl.shouldCenterTabs) return;
15026
16132
  if (index == null) index = ctrl.focusIndex;
15027
16133
  var tab = elements.tabs[index],
@@ -15055,7 +16161,7 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
15055
16161
  * Moves the indexes to their nearest valid values.
15056
16162
  */
15057
16163
  function refreshIndex () {
15058
- $scope.selectedIndex = getNearestSafeIndex($scope.selectedIndex);
16164
+ ctrl.selectedIndex = getNearestSafeIndex(ctrl.selectedIndex);
15059
16165
  ctrl.focusIndex = getNearestSafeIndex(ctrl.focusIndex);
15060
16166
  }
15061
16167
 
@@ -15064,9 +16170,9 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
15064
16170
  * @returns {*}
15065
16171
  */
15066
16172
  function updateHeightFromContent () {
15067
- if (!$scope.dynamicHeight) return $element.css('height', '');
16173
+ if (!ctrl.dynamicHeight) return $element.css('height', '');
15068
16174
  if (!ctrl.tabs.length) return queue.push(updateHeightFromContent);
15069
- var tabContent = elements.contents[$scope.selectedIndex],
16175
+ var tabContent = elements.contents[ctrl.selectedIndex],
15070
16176
  contentHeight = tabContent ? tabContent.offsetHeight : 0,
15071
16177
  tabsHeight = elements.wrapper.offsetHeight,
15072
16178
  newHeight = contentHeight + tabsHeight,
@@ -15090,16 +16196,23 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
15090
16196
  * @returns {*}
15091
16197
  */
15092
16198
  function updateInkBarStyles () {
15093
- if (!elements.tabs[$scope.selectedIndex]) return;
16199
+ if (!elements.tabs[ctrl.selectedIndex]) return;
15094
16200
  if (!ctrl.tabs.length) return queue.push(ctrl.updateInkBarStyles);
15095
16201
  //-- if the element is not visible, we will not be able to calculate sizes until it is
15096
16202
  //-- we should treat that as a resize event rather than just updating the ink bar
15097
16203
  if (!$element.prop('offsetParent')) return handleResizeWhenVisible();
15098
- var index = $scope.selectedIndex,
16204
+ var index = ctrl.selectedIndex,
15099
16205
  totalWidth = elements.paging.offsetWidth,
15100
16206
  tab = elements.tabs[index],
15101
16207
  left = tab.offsetLeft,
15102
- right = totalWidth - left - tab.offsetWidth;
16208
+ right = totalWidth - left - tab.offsetWidth,
16209
+ tabWidth;
16210
+ if (ctrl.shouldCenterTabs) {
16211
+ tabWidth = Array.prototype.slice.call(elements.tabs).reduce(function (value, element) {
16212
+ return value + element.offsetWidth;
16213
+ }, 0);
16214
+ if (totalWidth > tabWidth) $timeout(updateInkBarStyles, 0, false);
16215
+ }
15103
16216
  updateInkBarClassName();
15104
16217
  angular.element(elements.inkBar).css({ left: left + 'px', right: right + 'px' });
15105
16218
  }
@@ -15108,15 +16221,13 @@ function MdTabsController ($scope, $element, $window, $timeout, $mdConstant, $md
15108
16221
  * Adds left/right classes so that the ink bar will animate properly.
15109
16222
  */
15110
16223
  function updateInkBarClassName () {
15111
- var newIndex = $scope.selectedIndex,
16224
+ var newIndex = ctrl.selectedIndex,
15112
16225
  oldIndex = ctrl.lastSelectedIndex,
15113
16226
  ink = angular.element(elements.inkBar);
15114
16227
  if (!angular.isNumber(oldIndex)) return;
15115
- if (newIndex < oldIndex) {
15116
- ink.addClass('md-left').removeClass('md-right');
15117
- } else if (newIndex > oldIndex) {
15118
- ink.addClass('md-right').removeClass('md-left');
15119
- }
16228
+ ink
16229
+ .toggleClass('md-left', newIndex < oldIndex)
16230
+ .toggleClass('md-right', newIndex > oldIndex);
15120
16231
  }
15121
16232
 
15122
16233
  /**
@@ -15242,19 +16353,12 @@ angular
15242
16353
  function MdTabs ($mdTheming, $mdUtil, $compile) {
15243
16354
  return {
15244
16355
  scope: {
15245
- noPagination: '=?mdNoPagination',
15246
- dynamicHeight: '=?mdDynamicHeight',
15247
- centerTabs: '=?mdCenterTabs',
15248
16356
  selectedIndex: '=?mdSelected',
15249
- stretchTabs: '@?mdStretchTabs',
15250
- swipeContent: '=?mdSwipeContent',
15251
- noDisconnect: '=?mdNoDisconnect',
15252
- autoselect: '=?mdAutoselect'
15253
16357
  },
15254
16358
  template: function (element, attr) {
15255
16359
  attr["$mdTabsTemplate"] = element.html();
15256
16360
  return '\
15257
- <md-tabs-wrapper ng-class="{ \'md-stretch-tabs\': $mdTabsCtrl.shouldStretchTabs() }">\
16361
+ <md-tabs-wrapper>\
15258
16362
  <md-tab-data></md-tab-data>\
15259
16363
  <md-prev-button\
15260
16364
  tabindex="-1"\
@@ -15295,7 +16399,7 @@ function MdTabs ($mdTheming, $mdUtil, $compile) {
15295
16399
  style="max-width: {{ tabWidth ? tabWidth + \'px\' : \'none\' }}"\
15296
16400
  ng-repeat="tab in $mdTabsCtrl.tabs"\
15297
16401
  role="tab"\
15298
- aria-controls="tab-content-{{tab.id}}"\
16402
+ aria-controls="tab-content-{{::tab.id}}"\
15299
16403
  aria-selected="{{tab.isActive()}}"\
15300
16404
  aria-disabled="{{tab.scope.disabled || \'false\'}}"\
15301
16405
  ng-click="$mdTabsCtrl.select(tab.getIndex())"\
@@ -15307,34 +16411,34 @@ function MdTabs ($mdTheming, $mdUtil, $compile) {
15307
16411
  ng-disabled="tab.scope.disabled"\
15308
16412
  md-swipe-left="$mdTabsCtrl.nextPage()"\
15309
16413
  md-swipe-right="$mdTabsCtrl.previousPage()"\
15310
- md-template="tab.label"\
15311
- md-scope="tab.parent"></md-tab-item>\
15312
- <md-ink-bar ng-hide="noInkBar"></md-ink-bar>\
16414
+ md-template="::tab.label"\
16415
+ md-scope="::tab.parent"></md-tab-item>\
16416
+ <md-ink-bar></md-ink-bar>\
15313
16417
  </md-pagination-wrapper>\
15314
16418
  <div class="md-visually-hidden md-dummy-wrapper">\
15315
16419
  <md-dummy-tab\
15316
16420
  class="md-tab"\
15317
16421
  tabindex="-1"\
15318
- id="tab-item-{{tab.id}}"\
16422
+ id="tab-item-{{::tab.id}}"\
15319
16423
  role="tab"\
15320
- aria-controls="tab-content-{{tab.id}}"\
16424
+ aria-controls="tab-content-{{::tab.id}}"\
15321
16425
  aria-selected="{{tab.isActive()}}"\
15322
16426
  aria-disabled="{{tab.scope.disabled || \'false\'}}"\
15323
16427
  ng-focus="$mdTabsCtrl.hasFocus = true"\
15324
16428
  ng-blur="$mdTabsCtrl.hasFocus = false"\
15325
16429
  ng-repeat="tab in $mdTabsCtrl.tabs"\
15326
- md-template="tab.label"\
15327
- md-scope="tab.parent"></md-dummy-tab>\
16430
+ md-template="::tab.label"\
16431
+ md-scope="::tab.parent"></md-dummy-tab>\
15328
16432
  </div>\
15329
16433
  </md-tabs-canvas>\
15330
16434
  </md-tabs-wrapper>\
15331
16435
  <md-tabs-content-wrapper ng-show="$mdTabsCtrl.hasContent">\
15332
16436
  <md-tab-content\
15333
- id="tab-content-{{tab.id}}"\
16437
+ id="tab-content-{{::tab.id}}"\
15334
16438
  role="tabpanel"\
15335
- aria-labelledby="tab-item-{{tab.id}}"\
15336
- md-swipe-left="swipeContent && $mdTabsCtrl.incrementSelectedIndex(1)"\
15337
- md-swipe-right="swipeContent && $mdTabsCtrl.incrementSelectedIndex(-1)"\
16439
+ aria-labelledby="tab-item-{{::tab.id}}"\
16440
+ md-swipe-left="$mdTabsCtrl.swipeContent && $mdTabsCtrl.incrementSelectedIndex(1)"\
16441
+ md-swipe-right="$mdTabsCtrl.swipeContent && $mdTabsCtrl.incrementSelectedIndex(-1)"\
15338
16442
  ng-if="$mdTabsCtrl.hasContent"\
15339
16443
  ng-repeat="(index, tab) in $mdTabsCtrl.tabs"\
15340
16444
  md-connected-if="tab.isActive()"\
@@ -15343,18 +16447,19 @@ function MdTabs ($mdTheming, $mdUtil, $compile) {
15343
16447
  \'md-active\': tab.isActive(),\
15344
16448
  \'md-left\': tab.isLeft(),\
15345
16449
  \'md-right\': tab.isRight(),\
15346
- \'md-no-scroll\': dynamicHeight\
16450
+ \'md-no-scroll\': $mdTabsCtrl.dynamicHeight\
15347
16451
  }">\
15348
16452
  <div\
15349
- md-template="tab.template"\
15350
- md-scope="tab.parent"\
16453
+ md-template="::tab.template"\
16454
+ md-scope="::tab.parent"\
15351
16455
  ng-if="tab.shouldRender()"></div>\
15352
16456
  </md-tab-content>\
15353
16457
  </md-tabs-content-wrapper>\
15354
16458
  ';
15355
16459
  },
15356
16460
  controller: 'MdTabsController',
15357
- controllerAs: '$mdTabsCtrl'
16461
+ controllerAs: '$mdTabsCtrl',
16462
+ bindToController: true
15358
16463
  };
15359
16464
  }
15360
16465
  MdTabs.$inject = ["$mdTheming", "$mdUtil", "$compile"];
@@ -15383,6 +16488,10 @@ function MdTemplate ($compile, $mdUtil, $timeout) {
15383
16488
  var compileScope = scope.compileScope.$new();
15384
16489
  element.html(scope.template);
15385
16490
  $compile(element.contents())(compileScope);
16491
+ element.on('DOMSubtreeModified', function () {
16492
+ ctrl.updatePagination();
16493
+ ctrl.updateInkBarStyles();
16494
+ });
15386
16495
  return $timeout(handleScope);
15387
16496
  function handleScope () {
15388
16497
  scope.$watch('connected', function (value) { value === false ? disconnect() : reconnect(); });
@@ -15402,7 +16511,7 @@ MdTemplate.$inject = ["$compile", "$mdUtil", "$timeout"];
15402
16511
 
15403
16512
  })();
15404
16513
  (function(){
15405
- 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}}'; }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; }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-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-content.md-THEME_NAME-theme { background-color: '{{background-color}}'; }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-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-menu-content.md-THEME_NAME-theme { background-color: '{{background-color}}'; } md-menu-content.md-THEME_NAME-theme md-menu-divider { background-color: '{{foreground-4}}'; }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-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-sidenav.md-THEME_NAME-theme { background-color: '{{background-color}}'; }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}}'; }");
16514
+ 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-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-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-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-menu-content.md-THEME_NAME-theme { background-color: '{{background-color}}'; } md-menu-content.md-THEME_NAME-theme md-menu-divider { background-color: '{{foreground-4}}'; }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-select.md-THEME_NAME-theme .md-select-value { border-bottom-color: '{{foreground-4}}'; } md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder { color: '{{foreground-3}}'; }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-value { border-bottom-color: '{{primary-color}}'; color: '{{ foreground-1 }}'; } md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value.md-select-placeholder { color: '{{ foreground-1 }}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-value { border-bottom-color: '{{accent-color}}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-value { border-bottom-color: '{{warn-color}}'; }md-select.md-THEME_NAME-theme[disabled] .md-select-value { color: '{{foreground-3}}'; } md-select.md-THEME_NAME-theme[disabled] .md-select-value.md-select-placeholder { color: '{{foreground-3}}'; }md-select-menu.md-THEME_NAME-theme md-option[disabled] { color: '{{foreground-3}}'; }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-sidenav.md-THEME_NAME-theme { background-color: '{{background-color}}'; }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}}'; }");
15406
16515
  })();
15407
16516
 
15408
16517