2  * Angular Material Design
 
   3  * https://github.com/angular/material
 
   7 goog.provide('ngmaterial.components.toolbar');
 
   8 goog.require('ngmaterial.components.content');
 
   9 goog.require('ngmaterial.core');
 
  12  * @name material.components.toolbar
 
  14 mdToolbarDirective['$inject'] = ["$$rAF", "$mdConstant", "$mdUtil", "$mdTheming", "$animate"];
 
  15 angular.module('material.components.toolbar', [
 
  17   'material.components.content'
 
  19   .directive('mdToolbar', mdToolbarDirective);
 
  24  * @module material.components.toolbar
 
  27  * `md-toolbar` is used to place a toolbar in your app.
 
  29  * Toolbars are usually used above a content area to display the title of the
 
  30  * current page, and show relevant action buttons for that page.
 
  32  * You can change the height of the toolbar by adding either the
 
  33  * `md-medium-tall` or `md-tall` class to the toolbar.
 
  37  * <div layout="column" layout-fill>
 
  40  *     <div class="md-toolbar-tools">
 
  41  *       <h2 md-truncate flex>My App's Title</h2>
 
  55  * <i><b>Note:</b> The code above shows usage with the `md-truncate` component which provides an
 
  56  * ellipsis if the title is longer than the width of the Toolbar.</i>
 
  60  * The `<md-toolbar>` provides a few custom CSS classes that you may use to enhance the
 
  61  * functionality of your toolbar.
 
  64  * <docs-css-api-table>
 
  66  *   <docs-css-selector code="md-toolbar .md-toolbar-tools">
 
  67  *     The `md-toolbar-tools` class provides quite a bit of automatic styling for your toolbar
 
  68  *     buttons and text. When applied, it will center the buttons and text vertically for you.
 
  69  *   </docs-css-selector>
 
  71  * </docs-css-api-table>
 
  76  * Currently, the only private class is the `md-toolbar-transitions` class. All other classes are
 
  79  * @param {boolean=} md-scroll-shrink Whether the header should shrink away as
 
  80  * the user scrolls down, and reveal itself as the user scrolls up.
 
  82  * _**Note (1):** for scrollShrink to work, the toolbar must be a sibling of a
 
  83  * `md-content` element, placed before it. See the scroll shrink demo._
 
  85  * _**Note (2):** The `md-scroll-shrink` attribute is only parsed on component
 
  86  * initialization, it does not watch for scope changes._
 
  89  * @param {number=} md-shrink-speed-factor How much to change the speed of the toolbar's
 
  90  * shrinking by. For example, if 0.25 is given then the toolbar will shrink
 
  91  * at one fourth the rate at which the user scrolls down. Default 0.5.
 
  95 function mdToolbarDirective($$rAF, $mdConstant, $mdUtil, $mdTheming, $animate) {
 
  96   var translateY = angular.bind(null, $mdUtil.supplant, 'translate3d(0,{0}px,0)');
 
 102     link: function(scope, element, attr) {
 
 104       element.addClass('_md');     // private md component indicator for styling
 
 107       $mdUtil.nextTick(function () {
 
 108         element.addClass('_md-toolbar-transitions');     // adding toolbar transitions after digest
 
 111       if (angular.isDefined(attr.mdScrollShrink)) {
 
 115       function setupScrollShrink() {
 
 119         var disableScrollShrink = angular.noop;
 
 121         // Current "y" position of scroll
 
 122         // Store the last scroll top position
 
 124         var prevScrollTop = 0;
 
 125         var shrinkSpeedFactor = attr.mdShrinkSpeedFactor || 0.5;
 
 127         var debouncedContentScroll = $$rAF.throttle(onContentScroll);
 
 128         var debouncedUpdateHeight = $mdUtil.debounce(updateToolbarHeight, 5 * 1000);
 
 130         // Wait for $mdContentLoaded event from mdContent directive.
 
 131         // If the mdContent element is a sibling of our toolbar, hook it up
 
 134         scope.$on('$mdContentLoaded', onMdContentLoad);
 
 136         // If the toolbar is used inside an ng-if statement, we may miss the
 
 137         // $mdContentLoaded event, so we attempt to fake it if we have a
 
 138         // md-content close enough.
 
 140         attr.$observe('mdScrollShrink', onChangeScrollShrink);
 
 142         // If the toolbar has ngShow or ngHide we need to update height immediately as it changed
 
 143         // and not wait for $mdUtil.debounce to happen
 
 145         if (attr.ngShow) { scope.$watch(attr.ngShow, updateToolbarHeight); }
 
 146         if (attr.ngHide) { scope.$watch(attr.ngHide, updateToolbarHeight); }
 
 148         // If the scope is destroyed (which could happen with ng-if), make sure
 
 149         // to disable scroll shrinking again
 
 151         scope.$on('$destroy', disableScrollShrink);
 
 156         function onChangeScrollShrink(shrinkWithScroll) {
 
 157           var closestContent = element.parent().find('md-content');
 
 159           // If we have a content element, fake the call; this might still fail
 
 160           // if the content element isn't a sibling of the toolbar
 
 162           if (!contentElement && closestContent.length) {
 
 163             onMdContentLoad(null, closestContent);
 
 166           // Evaluate the expression
 
 167           shrinkWithScroll = scope.$eval(shrinkWithScroll);
 
 169           // Disable only if the attribute's expression evaluates to false
 
 170           if (shrinkWithScroll === false) {
 
 171             disableScrollShrink();
 
 173             disableScrollShrink = enableScrollShrink();
 
 180         function onMdContentLoad($event, newContentEl) {
 
 181           // Toolbar and content must be siblings
 
 182           if (newContentEl && element.parent()[0] === newContentEl.parent()[0]) {
 
 183             // unhook old content event listener if exists
 
 184             if (contentElement) {
 
 185               contentElement.off('scroll', debouncedContentScroll);
 
 188             contentElement = newContentEl;
 
 189             disableScrollShrink = enableScrollShrink();
 
 196         function onContentScroll(e) {
 
 197           var scrollTop = e ? e.target.scrollTop : prevScrollTop;
 
 199           debouncedUpdateHeight();
 
 202             toolbarHeight / shrinkSpeedFactor,
 
 203             Math.max(0, y + scrollTop - prevScrollTop)
 
 206           element.css($mdConstant.CSS.TRANSFORM, translateY([-y * shrinkSpeedFactor]));
 
 207           contentElement.css($mdConstant.CSS.TRANSFORM, translateY([(toolbarHeight - y) * shrinkSpeedFactor]));
 
 209           prevScrollTop = scrollTop;
 
 211           $mdUtil.nextTick(function() {
 
 212             var hasWhiteFrame = element.hasClass('md-whiteframe-z1');
 
 214             if (hasWhiteFrame && !y) {
 
 215               $animate.removeClass(element, 'md-whiteframe-z1');
 
 216             } else if (!hasWhiteFrame && y) {
 
 217               $animate.addClass(element, 'md-whiteframe-z1');
 
 226         function enableScrollShrink() {
 
 227           if (!contentElement)     return angular.noop;           // no md-content
 
 229           contentElement.on('scroll', debouncedContentScroll);
 
 230           contentElement.attr('scroll-shrink', 'true');
 
 232           $mdUtil.nextTick(updateToolbarHeight, false);
 
 234           return function disableScrollShrink() {
 
 235             contentElement.off('scroll', debouncedContentScroll);
 
 236             contentElement.attr('scroll-shrink', 'false');
 
 238             updateToolbarHeight();
 
 245         function updateToolbarHeight() {
 
 246           toolbarHeight = element.prop('offsetHeight');
 
 247           // Add a negative margin-top the size of the toolbar to the content el.
 
 248           // The content will start transformed down the toolbarHeight amount,
 
 249           // so everything looks normal.
 
 251           // As the user scrolls down, the content will be transformed up slowly
 
 252           // to put the content underneath where the toolbar was.
 
 253           var margin = (-toolbarHeight * shrinkSpeedFactor) + 'px';
 
 256             "margin-top": margin,
 
 257             "margin-bottom": margin
 
 270 ngmaterial.components.toolbar = angular.module("material.components.toolbar");