code: function listener(eventName, listenerFn, useCapture) {
      if (useCapture === void 0) { useCapture = false; }
      ngDevMode && assertPreviousIsParent();
      var node = previousOrParentNode;
      var native = node.native;
      ngDevMode && ngDevMode.rendererAddEventListener++;
      // In order to match current behavior, native DOM event listeners must be added for all
      // events (including outputs).
      if (isProceduralRenderer(renderer)) {
          var wrappedListener = wrapListenerWithDirtyLogic(viewData, listenerFn);
          var cleanupFn = renderer.listen(native, eventName, wrappedListener);
          storeCleanupFn(viewData, cleanupFn);
      }
      else {
          var wrappedListener = wrapListenerWithDirtyAndDefault(viewData, listenerFn);
          native.addEventListener(eventName, wrappedListener, useCapture);
          var cleanupInstances = getCleanup(viewData);
          cleanupInstances.push(wrappedListener);
          if (firstTemplatePass) {
              getTViewCleanup(viewData).push(eventName, node.tNode.index, cleanupInstances.length - 1, useCapture);
          }
      }
      var tNode = node.tNode;
      if (tNode.outputs === undefined) {
          // if we create TNode here, inputs must be undefined so we know they still need to be
          // checked
          tNode.outputs = generatePropertyAliases(node.tNode.flags, 1 /* Output */);
      }
      var outputs = tNode.outputs;
      var outputData;
      if (outputs && (outputData = outputs[eventName])) {
          createOutput(outputData, listenerFn);
      }
  }
docs: Adds an event listener to the current node.
  
  If an output exists on one of the node's directives, it also subscribes to the output
  and saves the subscription for later cleanup.
  
  @param eventName Name of the event
  @param listenerFn The function to be called when event emits
  @param useCapture Whether or not to use capture in event listener.