docs: function areAnimationsAllowed(element, parentElement, event) {
        var bodyElement = jqLite($document[0].body);
        var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
        var rootElementDetected = isMatchingElement(element, $rootElement);
        var parentAnimationDetected = false;
        var animateChildren;
        var elementDisabled = disabledElementsLookup.get(getDomNode(element));
  
        var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA);
        if (parentHost) {
          parentElement = parentHost;
        }
  
        parentElement = getDomNode(parentElement);
  
        while (parentElement) {
          if (!rootElementDetected) {
            // angular doesn't want to attempt to animate elements outside of the application
            // therefore we need to ensure that the rootElement is an ancestor of the current element
            rootElementDetected = isMatchingElement(parentElement, $rootElement);
          }
  
          if (parentElement.nodeType !== ELEMENT_NODE) {
            // no point in inspecting the #document element
            break;
          }
  
          var details = activeAnimationsLookup.get(parentElement) || {};
          // either an enter, leave or move animation will commence
          // therefore we can't allow any animations to take place
          // but if a parent animation is class-based then that's ok
          if (!parentAnimationDetected) {
            var parentElementDisabled = disabledElementsLookup.get(parentElement);
  
            if (parentElementDisabled === true && elementDisabled !== false) {
              // disable animations if the user hasn't explicitly enabled animations on the
              // current element
              elementDisabled = true;
              // element is disabled via parent element, no need to check anything else
              break;
            } else if (parentElementDisabled === false) {
              elementDisabled = false;
            }
            parentAnimationDetected = details.structural;
          }
  
          if (isUndefined(animateChildren) || animateChildren === true) {
            var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA);
            if (isDefined(value)) {
              animateChildren = value;
            }
          }
  
          // there is no need to continue traversing at this point
          if (parentAnimationDetected && animateChildren === false) break;
  
          if (!bodyElementDetected) {
            // we also need to ensure that the element is or will be a part of the body element
            // otherwise it is pointless to even issue an animation to be rendered
            bodyElementDetected = isMatchingElement(parentElement, bodyElement);
          }
  
          if (bodyElementDetected && rootElementDetected) {
            // If both body and root have been found, any other checks are pointless,
            // as no animation data should live outside the application
            break;
          }
  
          if (!rootElementDetected) {
            // If no rootElement is detected, check if the parentElement is pinned to another element
            parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA);
            if (parentHost) {
              // The pin target element becomes the next parent element
              parentElement = getDomNode(parentHost);
              continue;
            }
          }
  
          parentElement = parentElement.parentNode;
        }
  
        var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
        return allowAnimation && rootElementDetected && bodyElementDetected;
      }