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.

207 lines
6.6 KiB

  1. /*!
  2. * Angular Material Design
  3. * https://github.com/angular/material
  4. * @license MIT
  5. * v1.1.1
  6. */
  7. (function( window, angular, undefined ){
  8. "use strict";
  9. (function() {
  10. 'use strict';
  11. /**
  12. * @ngdoc module
  13. * @name material.components.fabToolbar
  14. */
  15. angular
  16. // Declare our module
  17. .module('material.components.fabToolbar', [
  18. 'material.core',
  19. 'material.components.fabShared',
  20. 'material.components.fabActions'
  21. ])
  22. // Register our directive
  23. .directive('mdFabToolbar', MdFabToolbarDirective)
  24. // Register our custom animations
  25. .animation('.md-fab-toolbar', MdFabToolbarAnimation)
  26. // Register a service for the animation so that we can easily inject it into unit tests
  27. .service('mdFabToolbarAnimation', MdFabToolbarAnimation);
  28. /**
  29. * @ngdoc directive
  30. * @name mdFabToolbar
  31. * @module material.components.fabToolbar
  32. *
  33. * @restrict E
  34. *
  35. * @description
  36. *
  37. * The `<md-fab-toolbar>` directive is used present a toolbar of elements (usually `<md-button>`s)
  38. * for quick access to common actions when a floating action button is activated (via click or
  39. * keyboard navigation).
  40. *
  41. * You may also easily position the trigger by applying one one of the following classes to the
  42. * `<md-fab-toolbar>` element:
  43. * - `md-fab-top-left`
  44. * - `md-fab-top-right`
  45. * - `md-fab-bottom-left`
  46. * - `md-fab-bottom-right`
  47. *
  48. * These CSS classes use `position: absolute`, so you need to ensure that the container element
  49. * also uses `position: absolute` or `position: relative` in order for them to work.
  50. *
  51. * @usage
  52. *
  53. * <hljs lang="html">
  54. * <md-fab-toolbar md-direction='left'>
  55. * <md-fab-trigger>
  56. * <md-button aria-label="Add..."><md-icon icon="/img/icons/plus.svg"></md-icon></md-button>
  57. * </md-fab-trigger>
  58. *
  59. * <md-toolbar>
  60. * <md-fab-actions>
  61. * <md-button aria-label="Add User">
  62. * <md-icon icon="/img/icons/user.svg"></md-icon>
  63. * </md-button>
  64. *
  65. * <md-button aria-label="Add Group">
  66. * <md-icon icon="/img/icons/group.svg"></md-icon>
  67. * </md-button>
  68. * </md-fab-actions>
  69. * </md-toolbar>
  70. * </md-fab-toolbar>
  71. * </hljs>
  72. *
  73. * @param {string} md-direction From which direction you would like the toolbar items to appear
  74. * relative to the trigger element. Supports `left` and `right` directions.
  75. * @param {expression=} md-open Programmatically control whether or not the toolbar is visible.
  76. */
  77. function MdFabToolbarDirective() {
  78. return {
  79. restrict: 'E',
  80. transclude: true,
  81. template: '<div class="md-fab-toolbar-wrapper">' +
  82. ' <div class="md-fab-toolbar-content" ng-transclude></div>' +
  83. '</div>',
  84. scope: {
  85. direction: '@?mdDirection',
  86. isOpen: '=?mdOpen'
  87. },
  88. bindToController: true,
  89. controller: 'MdFabController',
  90. controllerAs: 'vm',
  91. link: link
  92. };
  93. function link(scope, element, attributes) {
  94. // Add the base class for animations
  95. element.addClass('md-fab-toolbar');
  96. // Prepend the background element to the trigger's button
  97. element.find('md-fab-trigger').find('button')
  98. .prepend('<div class="md-fab-toolbar-background"></div>');
  99. }
  100. }
  101. function MdFabToolbarAnimation() {
  102. function runAnimation(element, className, done) {
  103. // If no className was specified, don't do anything
  104. if (!className) {
  105. return;
  106. }
  107. var el = element[0];
  108. var ctrl = element.controller('mdFabToolbar');
  109. // Grab the relevant child elements
  110. var backgroundElement = el.querySelector('.md-fab-toolbar-background');
  111. var triggerElement = el.querySelector('md-fab-trigger button');
  112. var toolbarElement = el.querySelector('md-toolbar');
  113. var iconElement = el.querySelector('md-fab-trigger button md-icon');
  114. var actions = element.find('md-fab-actions').children();
  115. // If we have both elements, use them to position the new background
  116. if (triggerElement && backgroundElement) {
  117. // Get our variables
  118. var color = window.getComputedStyle(triggerElement).getPropertyValue('background-color');
  119. var width = el.offsetWidth;
  120. var height = el.offsetHeight;
  121. // Make it twice as big as it should be since we scale from the center
  122. var scale = 2 * (width / triggerElement.offsetWidth);
  123. // Set some basic styles no matter what animation we're doing
  124. backgroundElement.style.backgroundColor = color;
  125. backgroundElement.style.borderRadius = width + 'px';
  126. // If we're open
  127. if (ctrl.isOpen) {
  128. // Turn on toolbar pointer events when closed
  129. toolbarElement.style.pointerEvents = 'inherit';
  130. backgroundElement.style.width = triggerElement.offsetWidth + 'px';
  131. backgroundElement.style.height = triggerElement.offsetHeight + 'px';
  132. backgroundElement.style.transform = 'scale(' + scale + ')';
  133. // Set the next close animation to have the proper delays
  134. backgroundElement.style.transitionDelay = '0ms';
  135. iconElement && (iconElement.style.transitionDelay = '.3s');
  136. // Apply a transition delay to actions
  137. angular.forEach(actions, function(action, index) {
  138. action.style.transitionDelay = (actions.length - index) * 25 + 'ms';
  139. });
  140. } else {
  141. // Turn off toolbar pointer events when closed
  142. toolbarElement.style.pointerEvents = 'none';
  143. // Scale it back down to the trigger's size
  144. backgroundElement.style.transform = 'scale(1)';
  145. // Reset the position
  146. backgroundElement.style.top = '0';
  147. if (element.hasClass('md-right')) {
  148. backgroundElement.style.left = '0';
  149. backgroundElement.style.right = null;
  150. }
  151. if (element.hasClass('md-left')) {
  152. backgroundElement.style.right = '0';
  153. backgroundElement.style.left = null;
  154. }
  155. // Set the next open animation to have the proper delays
  156. backgroundElement.style.transitionDelay = '200ms';
  157. iconElement && (iconElement.style.transitionDelay = '0ms');
  158. // Apply a transition delay to actions
  159. angular.forEach(actions, function(action, index) {
  160. action.style.transitionDelay = 200 + (index * 25) + 'ms';
  161. });
  162. }
  163. }
  164. }
  165. return {
  166. addClass: function(element, className, done) {
  167. runAnimation(element, className, done);
  168. done();
  169. },
  170. removeClass: function(element, className, done) {
  171. runAnimation(element, className, done);
  172. done();
  173. }
  174. }
  175. }
  176. })();
  177. })(window, window.angular);