UNPKG

angular-material-npfixed

Version:

The Angular Material project is an implementation of Material Design in Angular.js. This project provides a set of reusable, well-tested, and accessible Material Design UI components. Angular Material is supported internally at Google by the Angular.js, M

261 lines (217 loc) 8.51 kB
// Polyfill angular < 1.4 (provide $animateCss) angular .module('material.core') .factory('$$mdAnimate', function($q, $timeout, $mdConstant, $animateCss){ // Since $$mdAnimate is injected into $mdUtil... use a wrapper function // to subsequently inject $mdUtil as an argument to the AnimateDomUtils return function($mdUtil) { return AnimateDomUtils( $mdUtil, $q, $timeout, $mdConstant, $animateCss); }; }); /** * Factory function that requires special injections */ function AnimateDomUtils($mdUtil, $q, $timeout, $mdConstant, $animateCss) { var self; return self = { /** * */ translate3d : function( target, from, to, options ) { return $animateCss(target, { from: from, to: to, addClass: options.transitionInClass, removeClass: options.transitionOutClass, duration: options.duration }) .start() .then(function(){ // Resolve with reverser function... return reverseTranslate; }); /** * Specific reversal of the request translate animation above... */ function reverseTranslate (newFrom) { return $animateCss(target, { to: newFrom || from, addClass: options.transitionOutClass, removeClass: options.transitionInClass, duration: options.duration }).start(); } }, /** * Listen for transitionEnd event (with optional timeout) * Announce completion or failure via promise handlers */ waitTransitionEnd: function (element, opts) { var TIMEOUT = 3000; // fallback is 3 secs return $q(function(resolve, reject){ opts = opts || { }; // If there is no transition is found, resolve immediately // // NOTE: using $mdUtil.nextTick() causes delays/issues if (noTransitionFound(opts.cachedTransitionStyles)) { TIMEOUT = 0; } var timer = $timeout(finished, opts.timeout || TIMEOUT); element.on($mdConstant.CSS.TRANSITIONEND, finished); /** * Upon timeout or transitionEnd, reject or resolve (respectively) this promise. * NOTE: Make sure this transitionEnd didn't bubble up from a child */ function finished(ev) { if ( ev && ev.target !== element[0]) return; if ( ev ) $timeout.cancel(timer); element.off($mdConstant.CSS.TRANSITIONEND, finished); // Never reject since ngAnimate may cause timeouts due missed transitionEnd events resolve(); } /** * Checks whether or not there is a transition. * * @param styles The cached styles to use for the calculation. If null, getComputedStyle() * will be used. * * @returns {boolean} True if there is no transition/duration; false otherwise. */ function noTransitionFound(styles) { styles = styles || window.getComputedStyle(element[0]); return styles.transitionDuration == '0s' || (!styles.transition && !styles.transitionProperty); } }); }, calculateTransformValues: function (element, originator) { var origin = originator.element; var bounds = originator.bounds; if (origin || bounds) { var originBnds = origin ? self.clientRect(origin) || currentBounds() : self.copyRect(bounds); var dialogRect = self.copyRect(element[0].getBoundingClientRect()); var dialogCenterPt = self.centerPointFor(dialogRect); var originCenterPt = self.centerPointFor(originBnds); return { centerX: originCenterPt.x - dialogCenterPt.x, centerY: originCenterPt.y - dialogCenterPt.y, scaleX: Math.round(100 * Math.min(0.5, originBnds.width / dialogRect.width)) / 100, scaleY: Math.round(100 * Math.min(0.5, originBnds.height / dialogRect.height)) / 100 }; } return {centerX: 0, centerY: 0, scaleX: 0.5, scaleY: 0.5}; /** * This is a fallback if the origin information is no longer valid, then the * origin bounds simply becomes the current bounds for the dialogContainer's parent */ function currentBounds() { var cntr = element ? element.parent() : null; var parent = cntr ? cntr.parent() : null; return parent ? self.clientRect(parent) : null; } }, /** * Calculate the zoom transform from dialog to origin. * * We use this to set the dialog position immediately; * then the md-transition-in actually translates back to * `translate3d(0,0,0) scale(1.0)`... * * NOTE: all values are rounded to the nearest integer */ calculateZoomToOrigin: function (element, originator) { var zoomTemplate = "translate3d( {centerX}px, {centerY}px, 0 ) scale( {scaleX}, {scaleY} )"; var buildZoom = angular.bind(null, $mdUtil.supplant, zoomTemplate); return buildZoom(self.calculateTransformValues(element, originator)); }, /** * Calculate the slide transform from panel to origin. * NOTE: all values are rounded to the nearest integer */ calculateSlideToOrigin: function (element, originator) { var slideTemplate = "translate3d( {centerX}px, {centerY}px, 0 )"; var buildSlide = angular.bind(null, $mdUtil.supplant, slideTemplate); return buildSlide(self.calculateTransformValues(element, originator)); }, /** * Enhance raw values to represent valid css stylings... */ toCss : function( raw ) { var css = { }; var lookups = 'left top right bottom width height x y min-width min-height max-width max-height'; angular.forEach(raw, function(value,key) { if ( angular.isUndefined(value) ) return; if ( lookups.indexOf(key) >= 0 ) { css[key] = value + 'px'; } else { switch (key) { case 'transition': convertToVendor(key, $mdConstant.CSS.TRANSITION, value); break; case 'transform': convertToVendor(key, $mdConstant.CSS.TRANSFORM, value); break; case 'transformOrigin': convertToVendor(key, $mdConstant.CSS.TRANSFORM_ORIGIN, value); break; case 'font-size': css['font-size'] = value; // font sizes aren't always in px break; } } }); return css; function convertToVendor(key, vendor, value) { angular.forEach(vendor.split(' '), function (key) { css[key] = value; }); } }, /** * Convert the translate CSS value to key/value pair(s). */ toTransformCss: function (transform, addTransition, transition) { var css = {}; angular.forEach($mdConstant.CSS.TRANSFORM.split(' '), function (key) { css[key] = transform; }); if (addTransition) { transition = transition || "all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important"; css.transition = transition; } return css; }, /** * Clone the Rect and calculate the height/width if needed */ copyRect: function (source, destination) { if (!source) return null; destination = destination || {}; angular.forEach('left top right bottom width height'.split(' '), function (key) { destination[key] = Math.round(source[key]); }); destination.width = destination.width || (destination.right - destination.left); destination.height = destination.height || (destination.bottom - destination.top); return destination; }, /** * Calculate ClientRect of element; return null if hidden or zero size */ clientRect: function (element) { var bounds = angular.element(element)[0].getBoundingClientRect(); var isPositiveSizeClientRect = function (rect) { return rect && (rect.width > 0) && (rect.height > 0); }; // If the event origin element has zero size, it has probably been hidden. return isPositiveSizeClientRect(bounds) ? self.copyRect(bounds) : null; }, /** * Calculate 'rounded' center point of Rect */ centerPointFor: function (targetRect) { return targetRect ? { x: Math.round(targetRect.left + (targetRect.width / 2)), y: Math.round(targetRect.top + (targetRect.height / 2)) } : { x : 0, y : 0 }; } }; }