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.

208 lines
6.8 KiB

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