function onShow(scope, element, opts) {
      sanitizeAndConfigure(opts);

      if (opts.menuContentEl[0]) {
        // Inherit the theme from the target element.
        $mdTheming.inherit(opts.menuContentEl, opts.target);
      } else {
        $log.warn(
          '$mdMenu: Menu elements should always contain a `md-menu-content` element,' +
          'otherwise interactivity features will not work properly.',
          element
        );
      }

      // Register various listeners to move menu on resize/orientation change
      opts.cleanupResizing = startRepositioningOnResize();
      opts.hideBackdrop = showBackdrop(scope, element, opts);

      // Return the promise for when our menu is done animating in
      return showMenu()
        .then(function(response) {
          opts.alreadyOpen = true;
          opts.cleanupInteraction = activateInteraction();
          opts.cleanupBackdrop = setupBackdrop();

          // Since the menu finished its animation, mark the menu as clickable.
          element.addClass('md-clickable');

          return response;
        });

      /**
       * Place the menu into the DOM and call positioning related functions
       */
      function showMenu() {
        opts.parent.append(element);
        element[0].style.display = '';

        return $q(function(resolve) {
          var position = calculateMenuPosition(element, opts);

          element.removeClass('md-leave');

          // Animate the menu scaling, and opacity [from its position origin (default == top-left)]
          // to normal scale.
          $animateCss(element, {
            addClass: 'md-active',
            from: animator.toCss(position),
            to: animator.toCss({transform: ''})
          })
          .start()
          .then(resolve);

        });
      }

      /**
       * Check for valid opts and set some sane defaults
       */
      function sanitizeAndConfigure() {
        if (!opts.target) {
          throw Error(
            '$mdMenu.show() expected a target to animate from in options.target'
          );
        }
        angular.extend(opts, {
          alreadyOpen: false,
          isRemoved: false,
          target: angular.element(opts.target), // make sure it's not a naked DOM node
          parent: angular.element(opts.parent),
          menuContentEl: angular.element(element[0].querySelector('md-menu-content'))
        });
      }

      /**
       * Configure various resize listeners for screen changes
       */
      function startRepositioningOnResize() {

        var repositionMenu = (function(target, options) {
          return $$rAF.throttle(function() {
            if (opts.isRemoved) return;
            var position = calculateMenuPosition(target, options);

            target.css(animator.toCss(position));
          });
        })(element, opts);

        $window.addEventListener('resize', repositionMenu);
        $window.addEventListener('orientationchange', repositionMenu);

        return function stopRepositioningOnResize() {

          // Disable resizing handlers
          $window.removeEventListener('resize', repositionMenu);
          $window.removeEventListener('orientationchange', repositionMenu);

        };
      }

      /**
       * Sets up the backdrop and listens for click elements.
       * Once the backdrop will be clicked, the menu will automatically close.
       * @returns {!Function} Function to remove the backdrop.
       */
      function setupBackdrop() {
        if (!opts.backdrop) return angular.noop;

        opts.backdrop.on('click', onBackdropClick);

        return function() {
          opts.backdrop.off('click', onBackdropClick);
        };
      }

      /**
       * Function to be called whenever the backdrop is clicked.
       * @param {!MouseEvent} event
       */
      function onBackdropClick(event) {
        event.preventDefault();
        event.stopPropagation();

        scope.$apply(function() {
          opts.mdMenuCtrl.close(true, { closeAll: true });
        });
      }

      /**
       * Activate interaction on the menu. Resolves the focus target and closes the menu on
       * escape or option click.
       * @returns {!Function} Function to deactivate the interaction listeners.
       */
      function activateInteraction() {
        if (!opts.menuContentEl[0]) return angular.noop;

        // Wire up keyboard listeners.
        // - Close on escape,
        // - focus next item on down arrow,
        // - focus prev item on up
        opts.menuContentEl.on('keydown', onMenuKeyDown);
        opts.menuContentEl[0].addEventListener('click', captureClickListener, true);

        // kick off initial focus in the menu on the first enabled element
        var focusTarget = opts.menuContentEl[0]
          .querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));

        if (!focusTarget) {
          var childrenLen = opts.menuContentEl[0].children.length;
          for (var childIndex = 0; childIndex < childrenLen; childIndex++) {
            var child = opts.menuContentEl[0].children[childIndex];
            focusTarget = child.querySelector('.md-button:not([disabled])');
            if (focusTarget) {
              break;
            }
            if (child.firstElementChild && !child.firstElementChild.disabled) {
              focusTarget = child.firstElementChild;
              break;
            }
          }
        }

        focusTarget && focusTarget.focus();

        return function cleanupInteraction() {
          opts.menuContentEl.off('keydown', onMenuKeyDown);
          opts.menuContentEl[0].removeEventListener('click', captureClickListener, true);
        };

        // ************************************
        // internal functions
        // ************************************

        function onMenuKeyDown(ev) {
          var handled;
          switch (ev.keyCode) {
            case $mdConstant.KEY_CODE.ESCAPE:
              opts.mdMenuCtrl.close(false, { closeAll: true });
              handled = true;
              break;
            case $mdConstant.KEY_CODE.TAB:
              opts.mdMenuCtrl.close(false, { closeAll: true });
              // Don't prevent default or stop propagation on this event as we want tab
              // to move the focus to the next focusable element on the page.
              handled = false;
              break;
            case $mdConstant.KEY_CODE.UP_ARROW:
              if (!focusMenuItem(ev, opts.menuContentEl, opts, -1) && !opts.nestLevel) {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.DOWN_ARROW:
              if (!focusMenuItem(ev, opts.menuContentEl, opts, 1) && !opts.nestLevel) {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.LEFT_ARROW:
              if (opts.nestLevel) {
                opts.mdMenuCtrl.close();
              } else {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.RIGHT_ARROW:
              var parentMenu = $mdUtil.getClosest(ev.target, 'MD-MENU');
              if (parentMenu && parentMenu != opts.parent[0]) {
                ev.target.click();
              } else {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
          }
          if (handled) {
            ev.preventDefault();
            ev.stopImmediatePropagation();
          }
        }

        function onBackdropClick(e) {
          e.preventDefault();
          e.stopPropagation();
          scope.$apply(function() {
            opts.mdMenuCtrl.close(true, { closeAll: true });
          });
        }

        // Close menu on menu item click, if said menu-item is not disabled
        function captureClickListener(e) {
          var target = e.target;
          // Traverse up the event until we get to the menuContentEl to see if
          // there is an ng-click and that the ng-click is not disabled
          do {
            if (target == opts.menuContentEl[0]) return;
            if ((hasAnyAttribute(target, ['ng-click', 'ng-href', 'ui-sref']) ||
                target.nodeName == 'BUTTON' || target.nodeName == 'MD-BUTTON') && !hasAnyAttribute(target, ['md-prevent-menu-close'])) {
              var closestMenu = $mdUtil.getClosest(target, 'MD-MENU');
              if (!target.hasAttribute('disabled') && (!closestMenu || closestMenu == opts.parent[0])) {
                close();
              }
              break;
            }
          } while (target = target.parentNode);

          function close() {
            scope.$apply(function() {
              opts.mdMenuCtrl.close(true, { closeAll: true });
            });
          }

          function hasAnyAttribute(target, attrs) {
            if (!target) return false;

            for (var i = 0, attr; attr = attrs[i]; ++i) {
              if (prefixer.hasAttribute(target, attr)) {
                return true;
              }
            }

            return false;
          }
        }

      }
    }
function onShow(scope, element, opts) {
      sanitizeAndConfigure(opts);

      if (opts.menuContentEl[0]) {
        // Inherit the theme from the target element.
        $mdTheming.inherit(opts.menuContentEl, opts.target);
      } else {
        $log.warn(
          '$mdMenu: Menu elements should always contain a `md-menu-content` element,' +
          'otherwise interactivity features will not work properly.',
          element
        );
      }

      // Register various listeners to move menu on resize/orientation change
      opts.cleanupResizing = startRepositioningOnResize();
      opts.hideBackdrop = showBackdrop(scope, element, opts);

      // Return the promise for when our menu is done animating in
      return showMenu()
        .then(function(response) {
          opts.alreadyOpen = true;
          opts.cleanupInteraction = activateInteraction();
          opts.cleanupBackdrop = setupBackdrop();

          // Since the menu finished its animation, mark the menu as clickable.
          element.addClass('md-clickable');

          return response;
        });

      /**
       * Place the menu into the DOM and call positioning related functions
       */
      function showMenu() {
        opts.parent.append(element);
        element[0].style.display = '';

        return $q(function(resolve) {
          var position = calculateMenuPosition(element, opts);

          element.removeClass('md-leave');

          // Animate the menu scaling, and opacity [from its position origin (default == top-left)]
          // to normal scale.
          $animateCss(element, {
            addClass: 'md-active',
            from: animator.toCss(position),
            to: animator.toCss({transform: ''})
          })
          .start()
          .then(resolve);

        });
      }

      /**
       * Check for valid opts and set some sane defaults
       */
      function sanitizeAndConfigure() {
        if (!opts.target) {
          throw Error(
            '$mdMenu.show() expected a target to animate from in options.target'
          );
        }
        angular.extend(opts, {
          alreadyOpen: false,
          isRemoved: false,
          target: angular.element(opts.target), // make sure it's not a naked DOM node
          parent: angular.element(opts.parent),
          menuContentEl: angular.element(element[0].querySelector('md-menu-content'))
        });
      }

      /**
       * Configure various resize listeners for screen changes
       */
      function startRepositioningOnResize() {

        var repositionMenu = (function(target, options) {
          return $$rAF.throttle(function() {
            if (opts.isRemoved) return;
            var position = calculateMenuPosition(target, options);

            target.css(animator.toCss(position));
          });
        })(element, opts);

        $window.addEventListener('resize', repositionMenu);
        $window.addEventListener('orientationchange', repositionMenu);

        return function stopRepositioningOnResize() {

          // Disable resizing handlers
          $window.removeEventListener('resize', repositionMenu);
          $window.removeEventListener('orientationchange', repositionMenu);

        };
      }

      /**
       * Sets up the backdrop and listens for click elements.
       * Once the backdrop will be clicked, the menu will automatically close.
       * @returns {!Function} Function to remove the backdrop.
       */
      function setupBackdrop() {
        if (!opts.backdrop) return angular.noop;

        opts.backdrop.on('click', onBackdropClick);

        return function() {
          opts.backdrop.off('click', onBackdropClick);
        };
      }

      /**
       * Function to be called whenever the backdrop is clicked.
       * @param {!MouseEvent} event
       */
      function onBackdropClick(event) {
        event.preventDefault();
        event.stopPropagation();

        scope.$apply(function() {
          opts.mdMenuCtrl.close(true, { closeAll: true });
        });
      }

      /**
       * Activate interaction on the menu. Resolves the focus target and closes the menu on
       * escape or option click.
       * @returns {!Function} Function to deactivate the interaction listeners.
       */
      function activateInteraction() {
        if (!opts.menuContentEl[0]) return angular.noop;

        // Wire up keyboard listeners.
        // - Close on escape,
        // - focus next item on down arrow,
        // - focus prev item on up
        opts.menuContentEl.on('keydown', onMenuKeyDown);
        opts.menuContentEl[0].addEventListener('click', captureClickListener, true);

        // kick off initial focus in the menu on the first enabled element
        var focusTarget = opts.menuContentEl[0]
          .querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));

        if (!focusTarget) {
          var childrenLen = opts.menuContentEl[0].children.length;
          for (var childIndex = 0; childIndex < childrenLen; childIndex++) {
            var child = opts.menuContentEl[0].children[childIndex];
            focusTarget = child.querySelector('.md-button:not([disabled])');
            if (focusTarget) {
              break;
            }
            if (child.firstElementChild && !child.firstElementChild.disabled) {
              focusTarget = child.firstElementChild;
              break;
            }
          }
        }

        focusTarget && focusTarget.focus();

        return function cleanupInteraction() {
          opts.menuContentEl.off('keydown', onMenuKeyDown);
          opts.menuContentEl[0].removeEventListener('click', captureClickListener, true);
        };

        // ************************************
        // internal functions
        // ************************************

        function onMenuKeyDown(ev) {
          var handled;
          switch (ev.keyCode) {
            case $mdConstant.KEY_CODE.ESCAPE:
              opts.mdMenuCtrl.close(false, { closeAll: true });
              handled = true;
              break;
            case $mdConstant.KEY_CODE.TAB:
              opts.mdMenuCtrl.close(false, { closeAll: true });
              // Don't prevent default or stop propagation on this event as we want tab
              // to move the focus to the next focusable element on the page.
              handled = false;
              break;
            case $mdConstant.KEY_CODE.UP_ARROW:
              if (!focusMenuItem(ev, opts.menuContentEl, opts, -1) && !opts.nestLevel) {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.DOWN_ARROW:
              if (!focusMenuItem(ev, opts.menuContentEl, opts, 1) && !opts.nestLevel) {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.LEFT_ARROW:
              if (opts.nestLevel) {
                opts.mdMenuCtrl.close();
              } else {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
            case $mdConstant.KEY_CODE.RIGHT_ARROW:
              var parentMenu = $mdUtil.getClosest(ev.target, 'MD-MENU');
              if (parentMenu && parentMenu != opts.parent[0]) {
                ev.target.click();
              } else {
                opts.mdMenuCtrl.triggerContainerProxy(ev);
              }
              handled = true;
              break;
          }
          if (handled) {
            ev.preventDefault();
            ev.stopImmediatePropagation();
          }
        }

        function onBackdropClick(e) {
          e.preventDefault();
          e.stopPropagation();
          scope.$apply(function() {
            opts.mdMenuCtrl.close(true, { closeAll: true });
          });
        }

        // Close menu on menu item click, if said menu-item is not disabled
        function captureClickListener(e) {
          var target = e.target;
          // Traverse up the event until we get to the menuContentEl to see if
          // there is an ng-click and that the ng-click is not disabled
          do {
            if (target == opts.menuContentEl[0]) return;
            if ((hasAnyAttribute(target, ['ng-click', 'ng-href', 'ui-sref']) ||
                target.nodeName == 'BUTTON' || target.nodeName == 'MD-BUTTON') && !hasAnyAttribute(target, ['md-prevent-menu-close'])) {
              var closestMenu = $mdUtil.getClosest(target, 'MD-MENU');
              if (!target.hasAttribute('disabled') && (!closestMenu || closestMenu == opts.parent[0])) {
                close();
              }
              break;
            }
          } while (target = target.parentNode);

          function close() {
            scope.$apply(function() {
              opts.mdMenuCtrl.close(true, { closeAll: true });
            });
          }

          function hasAnyAttribute(target, attrs) {
            if (!target) return false;

            for (var i = 0, attr; attr = attrs[i]; ++i) {
              if (prefixer.hasAttribute(target, attr)) {
                return true;
              }
            }

            return false;
          }
        }

      }
    }
function onShow ( scope , element , opts ) { sanitizeAndConfigure ( opts ) ; if ( opts . menuContentEl [ 0 ] ) { // Inherit the theme from the target element. $mdTheming . inherit ( opts . menuContentEl , opts . target ) ; } else { $log . warn ( '$mdMenu: Menu elements should always contain a `md-menu-content` element,' + 'otherwise interactivity features will not work properly.' , element ) ; } // Register various listeners to move menu on resize/orientation change opts . cleanupResizing = startRepositioningOnResize ( ) ; opts . hideBackdrop = showBackdrop ( scope , element , opts ) ; // Return the promise for when our menu is done animating in return showMenu ( ) . then ( function ( response ) { opts . alreadyOpen = true ; opts . cleanupInteraction = activateInteraction ( ) ; opts . cleanupBackdrop = setupBackdrop ( ) ; // Since the menu finished its animation, mark the menu as clickable. element . addClass ( 'md-clickable' ) ; return response ; } ) ; /**
       * Place the menu into the DOM and call positioning related functions
       */ function showMenu ( ) { opts . parent . append ( element ) ; element [ 0 ] . style . display = '' ; return $q ( function ( resolve ) { var position = calculateMenuPosition ( element , opts ) ; element . removeClass ( 'md-leave' ) ; // Animate the menu scaling, and opacity [from its position origin (default == top-left)] // to normal scale. $animateCss ( element , { addClass : 'md-active' , from : animator . toCss ( position ) , to : animator . toCss ( { transform : '' } ) } ) . start ( ) . then ( resolve ) ; } ) ; } /**
       * Check for valid opts and set some sane defaults
       */ function sanitizeAndConfigure ( ) { if ( ! opts . target ) { throw Error ( '$mdMenu.show() expected a target to animate from in options.target' ) ; } angular . extend ( opts , { alreadyOpen : false , isRemoved : false , target : angular . element ( opts . target ) , // make sure it's not a naked DOM node parent : angular . element ( opts . parent ) , menuContentEl : angular . element ( element [ 0 ] . querySelector ( 'md-menu-content' ) ) } ) ; } /**
       * Configure various resize listeners for screen changes
       */ function startRepositioningOnResize ( ) { var repositionMenu = ( function ( target , options ) { return $$rAF . throttle ( function ( ) { if ( opts . isRemoved ) return ; var position = calculateMenuPosition ( target , options ) ; target . css ( animator . toCss ( position ) ) ; } ) ; } ) ( element , opts ) ; $window . addEventListener ( 'resize' , repositionMenu ) ; $window . addEventListener ( 'orientationchange' , repositionMenu ) ; return function stopRepositioningOnResize ( ) { // Disable resizing handlers $window . removeEventListener ( 'resize' , repositionMenu ) ; $window . removeEventListener ( 'orientationchange' , repositionMenu ) ; } ; } /**
       * Sets up the backdrop and listens for click elements.
       * Once the backdrop will be clicked, the menu will automatically close.
       * @returns {!Function} Function to remove the backdrop.
       */ function setupBackdrop ( ) { if ( ! opts . backdrop ) return angular . noop ; opts . backdrop . on ( 'click' , onBackdropClick ) ; return function ( ) { opts . backdrop . off ( 'click' , onBackdropClick ) ; } ; } /**
       * Function to be called whenever the backdrop is clicked.
       * @param {!MouseEvent} event
       */ function onBackdropClick ( event ) { event . preventDefault ( ) ; event . stopPropagation ( ) ; scope . $apply ( function ( ) { opts . mdMenuCtrl . close ( true , { closeAll : true } ) ; } ) ; } /**
       * Activate interaction on the menu. Resolves the focus target and closes the menu on
       * escape or option click.
       * @returns {!Function} Function to deactivate the interaction listeners.
       */ function activateInteraction ( ) { if ( ! opts . menuContentEl [ 0 ] ) return angular . noop ; // Wire up keyboard listeners. // - Close on escape, // - focus next item on down arrow, // - focus prev item on up opts . menuContentEl . on ( 'keydown' , onMenuKeyDown ) ; opts . menuContentEl [ 0 ] . addEventListener ( 'click' , captureClickListener , true ) ; // kick off initial focus in the menu on the first enabled element var focusTarget = opts . menuContentEl [ 0 ] . querySelector ( prefixer . buildSelector ( [ 'md-menu-focus-target' , 'md-autofocus' ] ) ) ; if ( ! focusTarget ) { var childrenLen = opts . menuContentEl [ 0 ] . children . length ; for ( var childIndex = 0 ; childIndex < childrenLen ; childIndex ++ ) { var child = opts . menuContentEl [ 0 ] . children [ childIndex ] ; focusTarget = child . querySelector ( '.md-button:not([disabled])' ) ; if ( focusTarget ) { break ; } if ( child . firstElementChild && ! child . firstElementChild . disabled ) { focusTarget = child . firstElementChild ; break ; } } } focusTarget && focusTarget . focus ( ) ; return function cleanupInteraction ( ) { opts . menuContentEl . off ( 'keydown' , onMenuKeyDown ) ; opts . menuContentEl [ 0 ] . removeEventListener ( 'click' , captureClickListener , true ) ; } ; // ************************************ // internal functions // ************************************ function onMenuKeyDown ( ev ) { var handled ; switch ( ev . keyCode ) { case $mdConstant . KEY_CODE . ESCAPE : opts . mdMenuCtrl . close ( false , { closeAll : true } ) ; handled = true ; break ; case $mdConstant . KEY_CODE . TAB : opts . mdMenuCtrl . close ( false , { closeAll : true } ) ; // Don't prevent default or stop propagation on this event as we want tab // to move the focus to the next focusable element on the page. handled = false ; break ; case $mdConstant . KEY_CODE . UP_ARROW : if ( ! focusMenuItem ( ev , opts . menuContentEl , opts , - 1 ) && ! opts . nestLevel ) { opts . mdMenuCtrl . triggerContainerProxy ( ev ) ; } handled = true ; break ; case $mdConstant . KEY_CODE . DOWN_ARROW : if ( ! focusMenuItem ( ev , opts . menuContentEl , opts , 1 ) && ! opts . nestLevel ) { opts . mdMenuCtrl . triggerContainerProxy ( ev ) ; } handled = true ; break ; case $mdConstant . KEY_CODE . LEFT_ARROW : if ( opts . nestLevel ) { opts . mdMenuCtrl . close ( ) ; } else { opts . mdMenuCtrl . triggerContainerProxy ( ev ) ; } handled = true ; break ; case $mdConstant . KEY_CODE . RIGHT_ARROW : var parentMenu = $mdUtil . getClosest ( ev . target , 'MD-MENU' ) ; if ( parentMenu && parentMenu != opts . parent [ 0 ] ) { ev . target . click ( ) ; } else { opts . mdMenuCtrl . triggerContainerProxy ( ev ) ; } handled = true ; break ; } if ( handled ) { ev . preventDefault ( ) ; ev . stopImmediatePropagation ( ) ; } } function onBackdropClick ( e ) { e . preventDefault ( ) ; e . stopPropagation ( ) ; scope . $apply ( function ( ) { opts . mdMenuCtrl . close ( true , { closeAll : true } ) ; } ) ; } // Close menu on menu item click, if said menu-item is not disabled function captureClickListener ( e ) { var target = e . target ; // Traverse up the event until we get to the menuContentEl to see if // there is an ng-click and that the ng-click is not disabled do { if ( target == opts . menuContentEl [ 0 ] ) return ; if ( ( hasAnyAttribute ( target , [ 'ng-click' , 'ng-href' , 'ui-sref' ] ) || target . nodeName == 'BUTTON' || target . nodeName == 'MD-BUTTON' ) && ! hasAnyAttribute ( target , [ 'md-prevent-menu-close' ] ) ) { var closestMenu = $mdUtil . getClosest ( target , 'MD-MENU' ) ; if ( ! target . hasAttribute ( 'disabled' ) && ( ! closestMenu || closestMenu == opts . parent [ 0 ] ) ) { close ( ) ; } break ; } } while ( target = target . parentNode ) ; function close ( ) { scope . $apply ( function ( ) { opts . mdMenuCtrl . close ( true , { closeAll : true } ) ; } ) ; } function hasAnyAttribute ( target , attrs ) { if ( ! target ) return false ; for ( var i = 0 , attr ; attr = attrs [ i ] ; ++ i ) { if ( prefixer . hasAttribute ( target , attr ) ) { return true ; } } return false ; } } } }
Inserts and configures the staged Menu element into the DOM, positioning it,
and wiring up various interaction events
Inserts and configures the staged Menu element into the DOM positioning it and wiring up various interaction events
Show the menu