| /*! |
| * Angular Material Design |
| * https://github.com/angular/material |
| * @license MIT |
| * v1.0.1 |
| */ |
| (function( window, angular, undefined ){ |
| "use strict"; |
| |
| /** |
| * @ngdoc module |
| * @name material.components.toolbar |
| */ |
| angular.module('material.components.toolbar', [ |
| 'material.core', |
| 'material.components.content' |
| ]) |
| .directive('mdToolbar', mdToolbarDirective); |
| |
| /** |
| * @ngdoc directive |
| * @name mdToolbar |
| * @module material.components.toolbar |
| * @restrict E |
| * @description |
| * `md-toolbar` is used to place a toolbar in your app. |
| * |
| * Toolbars are usually used above a content area to display the title of the |
| * current page, and show relevant action buttons for that page. |
| * |
| * You can change the height of the toolbar by adding either the |
| * `md-medium-tall` or `md-tall` class to the toolbar. |
| * |
| * @usage |
| * <hljs lang="html"> |
| * <div layout="column" layout-fill> |
| * <md-toolbar> |
| * |
| * <div class="md-toolbar-tools"> |
| * <span>My App's Title</span> |
| * |
| * <!-- fill up the space between left and right area --> |
| * <span flex></span> |
| * |
| * <md-button> |
| * Right Bar Button |
| * </md-button> |
| * </div> |
| * |
| * </md-toolbar> |
| * <md-content> |
| * Hello! |
| * </md-content> |
| * </div> |
| * </hljs> |
| * |
| * @param {boolean=} md-scroll-shrink Whether the header should shrink away as |
| * the user scrolls down, and reveal itself as the user scrolls up. |
| * |
| * _**Note (1):** for scrollShrink to work, the toolbar must be a sibling of a |
| * `md-content` element, placed before it. See the scroll shrink demo._ |
| * |
| * _**Note (2):** The `md-scroll-shrink` attribute is only parsed on component |
| * initialization, it does not watch for scope changes._ |
| * |
| * |
| * @param {number=} md-shrink-speed-factor How much to change the speed of the toolbar's |
| * shrinking by. For example, if 0.25 is given then the toolbar will shrink |
| * at one fourth the rate at which the user scrolls down. Default 0.5. |
| */ |
| |
| function mdToolbarDirective($$rAF, $mdConstant, $mdUtil, $mdTheming, $animate) { |
| var translateY = angular.bind(null, $mdUtil.supplant, 'translate3d(0,{0}px,0)'); |
| |
| return { |
| template: '', |
| |
| restrict: 'E', |
| |
| link: function(scope, element, attr) { |
| |
| $mdTheming(element); |
| |
| if (angular.isDefined(attr.mdScrollShrink)) { |
| setupScrollShrink(); |
| } |
| |
| function setupScrollShrink() { |
| |
| var toolbarHeight; |
| var contentElement; |
| var disableScrollShrink = angular.noop; |
| |
| // Current "y" position of scroll |
| // Store the last scroll top position |
| var y = 0; |
| var prevScrollTop = 0; |
| var shrinkSpeedFactor = attr.mdShrinkSpeedFactor || 0.5; |
| |
| var debouncedContentScroll = $$rAF.throttle(onContentScroll); |
| var debouncedUpdateHeight = $mdUtil.debounce(updateToolbarHeight, 5 * 1000); |
| |
| // Wait for $mdContentLoaded event from mdContent directive. |
| // If the mdContent element is a sibling of our toolbar, hook it up |
| // to scroll events. |
| |
| scope.$on('$mdContentLoaded', onMdContentLoad); |
| |
| // If the toolbar is used inside an ng-if statement, we may miss the |
| // $mdContentLoaded event, so we attempt to fake it if we have a |
| // md-content close enough. |
| |
| attr.$observe('mdScrollShrink', onChangeScrollShrink); |
| |
| // If the toolbar has ngShow or ngHide we need to update height immediately as it changed |
| // and not wait for $mdUtil.debounce to happen |
| |
| if (attr.ngShow) { scope.$watch(attr.ngShow, updateToolbarHeight); } |
| if (attr.ngHide) { scope.$watch(attr.ngHide, updateToolbarHeight); } |
| |
| // If the scope is destroyed (which could happen with ng-if), make sure |
| // to disable scroll shrinking again |
| |
| scope.$on('$destroy', disableScrollShrink); |
| |
| /** |
| * |
| */ |
| function onChangeScrollShrink(shrinkWithScroll) { |
| var closestContent = element.parent().find('md-content'); |
| |
| // If we have a content element, fake the call; this might still fail |
| // if the content element isn't a sibling of the toolbar |
| |
| if (!contentElement && closestContent.length) { |
| onMdContentLoad(null, closestContent); |
| } |
| |
| // Evaluate the expression |
| shrinkWithScroll = scope.$eval(shrinkWithScroll); |
| |
| // Disable only if the attribute's expression evaluates to false |
| if (shrinkWithScroll === false) { |
| disableScrollShrink(); |
| } else { |
| disableScrollShrink = enableScrollShrink(); |
| } |
| } |
| |
| /** |
| * |
| */ |
| function onMdContentLoad($event, newContentEl) { |
| // Toolbar and content must be siblings |
| if (newContentEl && element.parent()[0] === newContentEl.parent()[0]) { |
| // unhook old content event listener if exists |
| if (contentElement) { |
| contentElement.off('scroll', debouncedContentScroll); |
| } |
| |
| contentElement = newContentEl; |
| disableScrollShrink = enableScrollShrink(); |
| } |
| } |
| |
| /** |
| * |
| */ |
| function onContentScroll(e) { |
| var scrollTop = e ? e.target.scrollTop : prevScrollTop; |
| |
| debouncedUpdateHeight(); |
| |
| y = Math.min( |
| toolbarHeight / shrinkSpeedFactor, |
| Math.max(0, y + scrollTop - prevScrollTop) |
| ); |
| |
| element.css($mdConstant.CSS.TRANSFORM, translateY([-y * shrinkSpeedFactor])); |
| contentElement.css($mdConstant.CSS.TRANSFORM, translateY([(toolbarHeight - y) * shrinkSpeedFactor])); |
| |
| prevScrollTop = scrollTop; |
| |
| $mdUtil.nextTick(function() { |
| var hasWhiteFrame = element.hasClass('md-whiteframe-z1'); |
| |
| if (hasWhiteFrame && !y) { |
| $animate.removeClass(element, 'md-whiteframe-z1'); |
| } else if (!hasWhiteFrame && y) { |
| $animate.addClass(element, 'md-whiteframe-z1'); |
| } |
| }); |
| |
| } |
| |
| /** |
| * |
| */ |
| function enableScrollShrink() { |
| if (!contentElement) return angular.noop; // no md-content |
| |
| contentElement.on('scroll', debouncedContentScroll); |
| contentElement.attr('scroll-shrink', 'true'); |
| |
| $$rAF(updateToolbarHeight); |
| |
| return function disableScrollShrink() { |
| contentElement.off('scroll', debouncedContentScroll); |
| contentElement.attr('scroll-shrink', 'false'); |
| |
| $$rAF(updateToolbarHeight); |
| } |
| } |
| |
| /** |
| * |
| */ |
| function updateToolbarHeight() { |
| toolbarHeight = element.prop('offsetHeight'); |
| // Add a negative margin-top the size of the toolbar to the content el. |
| // The content will start transformed down the toolbarHeight amount, |
| // so everything looks normal. |
| // |
| // As the user scrolls down, the content will be transformed up slowly |
| // to put the content underneath where the toolbar was. |
| var margin = (-toolbarHeight * shrinkSpeedFactor) + 'px'; |
| |
| contentElement.css({ |
| "margin-top": margin, |
| "margin-bottom": margin |
| }); |
| |
| onContentScroll(); |
| } |
| |
| } |
| |
| } |
| }; |
| |
| } |
| mdToolbarDirective.$inject = ["$$rAF", "$mdConstant", "$mdUtil", "$mdTheming", "$animate"]; |
| |
| })(window, window.angular); |