You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
8.3 KiB

7 years ago
  1. /*!
  2. * Angular Material Design
  3. * https://github.com/angular/material
  4. * @license MIT
  5. * v1.1.3
  6. */
  7. goog.provide('ngmaterial.components.toolbar');
  8. goog.require('ngmaterial.components.content');
  9. goog.require('ngmaterial.core');
  10. /**
  11. * @ngdoc module
  12. * @name material.components.toolbar
  13. */
  14. mdToolbarDirective['$inject'] = ["$$rAF", "$mdConstant", "$mdUtil", "$mdTheming", "$animate"];
  15. angular.module('material.components.toolbar', [
  16. 'material.core',
  17. 'material.components.content'
  18. ])
  19. .directive('mdToolbar', mdToolbarDirective);
  20. /**
  21. * @ngdoc directive
  22. * @name mdToolbar
  23. * @module material.components.toolbar
  24. * @restrict E
  25. * @description
  26. * `md-toolbar` is used to place a toolbar in your app.
  27. *
  28. * Toolbars are usually used above a content area to display the title of the
  29. * current page, and show relevant action buttons for that page.
  30. *
  31. * You can change the height of the toolbar by adding either the
  32. * `md-medium-tall` or `md-tall` class to the toolbar.
  33. *
  34. * @usage
  35. * <hljs lang="html">
  36. * <div layout="column" layout-fill>
  37. * <md-toolbar>
  38. *
  39. * <div class="md-toolbar-tools">
  40. * <h2 md-truncate flex>My App's Title</h2>
  41. *
  42. * <md-button>
  43. * Right Bar Button
  44. * </md-button>
  45. * </div>
  46. *
  47. * </md-toolbar>
  48. * <md-content>
  49. * Hello!
  50. * </md-content>
  51. * </div>
  52. * </hljs>
  53. *
  54. * <i><b>Note:</b> The code above shows usage with the `md-truncate` component which provides an
  55. * ellipsis if the title is longer than the width of the Toolbar.</i>
  56. *
  57. * ## CSS & Styles
  58. *
  59. * The `<md-toolbar>` provides a few custom CSS classes that you may use to enhance the
  60. * functionality of your toolbar.
  61. *
  62. * <div>
  63. * <docs-css-api-table>
  64. *
  65. * <docs-css-selector code="md-toolbar .md-toolbar-tools">
  66. * The `md-toolbar-tools` class provides quite a bit of automatic styling for your toolbar
  67. * buttons and text. When applied, it will center the buttons and text vertically for you.
  68. * </docs-css-selector>
  69. *
  70. * </docs-css-api-table>
  71. * </div>
  72. *
  73. * ### Private Classes
  74. *
  75. * Currently, the only private class is the `md-toolbar-transitions` class. All other classes are
  76. * considered public.
  77. *
  78. * @param {boolean=} md-scroll-shrink Whether the header should shrink away as
  79. * the user scrolls down, and reveal itself as the user scrolls up.
  80. *
  81. * _**Note (1):** for scrollShrink to work, the toolbar must be a sibling of a
  82. * `md-content` element, placed before it. See the scroll shrink demo._
  83. *
  84. * _**Note (2):** The `md-scroll-shrink` attribute is only parsed on component
  85. * initialization, it does not watch for scope changes._
  86. *
  87. *
  88. * @param {number=} md-shrink-speed-factor How much to change the speed of the toolbar's
  89. * shrinking by. For example, if 0.25 is given then the toolbar will shrink
  90. * at one fourth the rate at which the user scrolls down. Default 0.5.
  91. *
  92. */
  93. function mdToolbarDirective($$rAF, $mdConstant, $mdUtil, $mdTheming, $animate) {
  94. var translateY = angular.bind(null, $mdUtil.supplant, 'translate3d(0,{0}px,0)');
  95. return {
  96. template: '',
  97. restrict: 'E',
  98. link: function(scope, element, attr) {
  99. element.addClass('_md'); // private md component indicator for styling
  100. $mdTheming(element);
  101. $mdUtil.nextTick(function () {
  102. element.addClass('_md-toolbar-transitions'); // adding toolbar transitions after digest
  103. }, false);
  104. if (angular.isDefined(attr.mdScrollShrink)) {
  105. setupScrollShrink();
  106. }
  107. function setupScrollShrink() {
  108. var toolbarHeight;
  109. var contentElement;
  110. var disableScrollShrink = angular.noop;
  111. // Current "y" position of scroll
  112. // Store the last scroll top position
  113. var y = 0;
  114. var prevScrollTop = 0;
  115. var shrinkSpeedFactor = attr.mdShrinkSpeedFactor || 0.5;
  116. var debouncedContentScroll = $$rAF.throttle(onContentScroll);
  117. var debouncedUpdateHeight = $mdUtil.debounce(updateToolbarHeight, 5 * 1000);
  118. // Wait for $mdContentLoaded event from mdContent directive.
  119. // If the mdContent element is a sibling of our toolbar, hook it up
  120. // to scroll events.
  121. scope.$on('$mdContentLoaded', onMdContentLoad);
  122. // If the toolbar is used inside an ng-if statement, we may miss the
  123. // $mdContentLoaded event, so we attempt to fake it if we have a
  124. // md-content close enough.
  125. attr.$observe('mdScrollShrink', onChangeScrollShrink);
  126. // If the toolbar has ngShow or ngHide we need to update height immediately as it changed
  127. // and not wait for $mdUtil.debounce to happen
  128. if (attr.ngShow) { scope.$watch(attr.ngShow, updateToolbarHeight); }
  129. if (attr.ngHide) { scope.$watch(attr.ngHide, updateToolbarHeight); }
  130. // If the scope is destroyed (which could happen with ng-if), make sure
  131. // to disable scroll shrinking again
  132. scope.$on('$destroy', disableScrollShrink);
  133. /**
  134. *
  135. */
  136. function onChangeScrollShrink(shrinkWithScroll) {
  137. var closestContent = element.parent().find('md-content');
  138. // If we have a content element, fake the call; this might still fail
  139. // if the content element isn't a sibling of the toolbar
  140. if (!contentElement && closestContent.length) {
  141. onMdContentLoad(null, closestContent);
  142. }
  143. // Evaluate the expression
  144. shrinkWithScroll = scope.$eval(shrinkWithScroll);
  145. // Disable only if the attribute's expression evaluates to false
  146. if (shrinkWithScroll === false) {
  147. disableScrollShrink();
  148. } else {
  149. disableScrollShrink = enableScrollShrink();
  150. }
  151. }
  152. /**
  153. *
  154. */
  155. function onMdContentLoad($event, newContentEl) {
  156. // Toolbar and content must be siblings
  157. if (newContentEl && element.parent()[0] === newContentEl.parent()[0]) {
  158. // unhook old content event listener if exists
  159. if (contentElement) {
  160. contentElement.off('scroll', debouncedContentScroll);
  161. }
  162. contentElement = newContentEl;
  163. disableScrollShrink = enableScrollShrink();
  164. }
  165. }
  166. /**
  167. *
  168. */
  169. function onContentScroll(e) {
  170. var scrollTop = e ? e.target.scrollTop : prevScrollTop;
  171. debouncedUpdateHeight();
  172. y = Math.min(
  173. toolbarHeight / shrinkSpeedFactor,
  174. Math.max(0, y + scrollTop - prevScrollTop)
  175. );
  176. element.css($mdConstant.CSS.TRANSFORM, translateY([-y * shrinkSpeedFactor]));
  177. contentElement.css($mdConstant.CSS.TRANSFORM, translateY([(toolbarHeight - y) * shrinkSpeedFactor]));
  178. prevScrollTop = scrollTop;
  179. $mdUtil.nextTick(function() {
  180. var hasWhiteFrame = element.hasClass('md-whiteframe-z1');
  181. if (hasWhiteFrame && !y) {
  182. $animate.removeClass(element, 'md-whiteframe-z1');
  183. } else if (!hasWhiteFrame && y) {
  184. $animate.addClass(element, 'md-whiteframe-z1');
  185. }
  186. });
  187. }
  188. /**
  189. *
  190. */
  191. function enableScrollShrink() {
  192. if (!contentElement) return angular.noop; // no md-content
  193. contentElement.on('scroll', debouncedContentScroll);
  194. contentElement.attr('scroll-shrink', 'true');
  195. $mdUtil.nextTick(updateToolbarHeight, false);
  196. return function disableScrollShrink() {
  197. contentElement.off('scroll', debouncedContentScroll);
  198. contentElement.attr('scroll-shrink', 'false');
  199. updateToolbarHeight();
  200. };
  201. }
  202. /**
  203. *
  204. */
  205. function updateToolbarHeight() {
  206. toolbarHeight = element.prop('offsetHeight');
  207. // Add a negative margin-top the size of the toolbar to the content el.
  208. // The content will start transformed down the toolbarHeight amount,
  209. // so everything looks normal.
  210. //
  211. // As the user scrolls down, the content will be transformed up slowly
  212. // to put the content underneath where the toolbar was.
  213. var margin = (-toolbarHeight * shrinkSpeedFactor) + 'px';
  214. contentElement.css({
  215. "margin-top": margin,
  216. "margin-bottom": margin
  217. });
  218. onContentScroll();
  219. }
  220. }
  221. }
  222. };
  223. }
  224. ngmaterial.components.toolbar = angular.module("material.components.toolbar");