text: var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
  };
  var __metadata = (this && this.__metadata) || function (k, v) {
      if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
  };
  import { Directive, ElementRef, EventEmitter, Injectable, NgZone, Optional, Output, Renderer, SkipSelf } from '@angular/core';
  import { Subject } from 'rxjs/Subject';
  // This is the value used by AngularJS Material. Through trial and error (on iPhone 6S) they found
  // that a value of around 650ms seems appropriate.
  export var TOUCH_BUFFER_MS = 650;
  /** Monitors mouse and keyboard events to determine the cause of focus events. */
  var FocusOriginMonitor = (function () {
      function FocusOriginMonitor(_ngZone) {
          var _this = this;
          this._ngZone = _ngZone;
          /** The focus origin that the next focus event is a result of. */
          this._origin = null;
          /** Whether the window has just been focused. */
          this._windowFocused = false;
          /** Weak map of elements being monitored to their info. */
          this._elementInfo = new WeakMap();
          this._ngZone.runOutsideAngular(function () { return _this._registerDocumentEvents(); });
      }
      /**
       * Monitors focus on an element and applies appropriate CSS classes.
       * @param element The element to monitor
       * @param renderer The renderer to use to apply CSS classes to the element.
       * @param checkChildren Whether to count the element as focused when its children are focused.
       * @returns An observable that emits when the focus state of the element changes.
       *     When the element is blurred, null will be emitted.
       */
      FocusOriginMonitor.prototype.monitor = function (element, renderer, checkChildren) {
          var _this = this;
          // Check if we're already monitoring this element.
          if (this._elementInfo.has(element)) {
              var info_1 = this._elementInfo.get(element);
              info_1.checkChildren = checkChildren;
              return info_1.subject.asObservable();
          }
          // Create monitored element info.
          var info = {
              unlisten: null,
              checkChildren: checkChildren,
              renderer: renderer,
              subject: new Subject()
          };
          this._elementInfo.set(element, info);
          // Start listening. We need to listen in capture phase since focus events don't bubble.
          var focusListener = function (event) { return _this._onFocus(event, element); };
          var blurListener = function (event) { return _this._onBlur(event, element); };
          this._ngZone.runOutsideAngular(function () {
              element.addEventListener('focus', focusListener, true);
              element.addEventListener('blur', blurListener, true);
          });
          // Create an unlisten function for later.
          info.unlisten = function () {
              element.removeEventListener('focus', focusListener, true);
              element.removeEventListener('blur', blurListener, true);
          };
          return info.subject.asObservable();
      };
      /**
       * Stops monitoring an element and removes all focus classes.
       * @param element The element to stop monitoring.
       */
      FocusOriginMonitor.prototype.unmonitor = function (element) {
          var elementInfo = this._elementInfo.get(element);
          if (elementInfo) {
              elementInfo.unlisten();
              elementInfo.subject.complete();
              this._setClasses(element, null);
              this._elementInfo.delete(element);
          }
      };
      /**
       * Focuses the element via the specified focus origin.
       * @param element The element to focus.
       * @param renderer The renderer to use to invoke the focus method on the element.
       * @param origin The focus origin.
       */
      FocusOriginMonitor.prototype.focusVia = function (element, renderer, origin) {
          this._setOriginForCurrentEventQueue(origin);
          renderer.invokeElementMethod(element, 'focus');
      };
      /** Register necessary event listeners on the document and window. */
      FocusOriginMonitor.prototype._registerDocumentEvents = function () {
          // Note: we listen to events in the capture phase so we can detect them even if the user stops
          // propagation.
          var _this = this;
          // On keydown record the origin and clear any touch event that may be in progress.
          document.addEventListener('keydown', function () {
              _this._lastTouchTarget = null;
              _this._setOriginForCurrentEventQueue('keyboard');
          }, true);
          // On mousedown record the origin only if there is not touch target, since a mousedown can
          // happen as a result of a touch event.
          document.addEventListener('mousedown', function () {
              if (!_this._lastTouchTarget) {
                  _this._setOriginForCurrentEventQueue('mouse');
              }
          }, true);
          // When the touchstart event fires the focus event is not yet in the event queue. This means
          // we can't rely on the trick used above (setting timeout of 0ms). Instead we wait 650ms to
          // see if a focus happens.
          document.addEventListener('touchstart', function (event) {
              if (_this._touchTimeout != null) {
                  clearTimeout(_this._touchTimeout);
              }
              _this._lastTouchTarget = event.target;
              _this._touchTimeout = setTimeout(function () { return _this._lastTouchTarget = null; }, TOUCH_BUFFER_MS);
          }, true);
          // Make a note of when the window regains focus, so we can restore the origin info for the
          // focused element.
          window.addEventListener('focus', function () {
              _this._windowFocused = true;
              setTimeout(function () { return _this._windowFocused = false; }, 0);
          });
      };
      /**
       * Sets the focus classes on the element based on the given focus origin.
       * @param element The element to update the classes on.
       * @param origin The focus origin.
       */
      FocusOriginMonitor.prototype._setClasses = function (element, origin) {
          var renderer = this._elementInfo.get(element).renderer;
          renderer.setElementClass(element, 'cdk-focused', !!origin);
          renderer.setElementClass(element, 'cdk-touch-focused', origin === 'touch');
          renderer.setElementClass(element, 'cdk-keyboard-focused', origin === 'keyboard');
          renderer.setElementClass(element, 'cdk-mouse-focused', origin === 'mouse');
          renderer.setElementClass(element, 'cdk-program-focused', origin === 'program');
      };
      /**
       * Sets the origin and schedules an async function to clear it at the end of the event queue.
       * @param origin The origin to set.
       */
      FocusOriginMonitor.prototype._setOriginForCurrentEventQueue = function (origin) {
          var _this = this;
          this._origin = origin;
          setTimeout(function () { return _this._origin = null; }, 0);
      };
      /**
       * Checks whether the given focus event was caused by a touchstart event.
       * @param event The focus event to check.
       * @returns Whether the event was caused by a touch.
       */
      FocusOriginMonitor.prototype._wasCausedByTouch = function (event) {
          // Note(mmalerba): This implementation is not quite perfect, there is a small edge case.
          // Consider the following dom structure:
          //
          // <div #parent tabindex="0" cdkFocusClasses>
          //   <div #child (click)="#parent.focus()"></div>
          // </div>
          //
          // If the user touches the #child element and the #parent is programmatically focused as a
          // result, this code will still consider it to have been caused by the touch event and will
          // apply the cdk-touch-focused class rather than the cdk-program-focused class. This is a
          // relatively small edge-case that can be worked around by using
          // focusVia(parentEl, renderer,  'program') to focus the parent element.
          //
          // If we decide that we absolutely must handle this case correctly, we can do so by listening
          // for the first focus event after the touchstart, and then the first blur event after that
          // focus event. When that blur event fires we know that whatever follows is not a result of the
          // touchstart.
          var focusTarget = event.target;
          return this._lastTouchTarget instanceof Node && focusTarget instanceof Node &&
              (focusTarget === this._lastTouchTarget || focusTarget.contains(this._lastTouchTarget));
      };
      /**
       * Handles focus events on a registered element.
       * @param event The focus event.
       * @param element The monitored element.
       */
      FocusOriginMonitor.prototype._onFocus = function (event, element) {
          // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
          // focus event affecting the monitored element. If we want to use the origin of the first event
          // instead we should check for the cdk-focused class here and return if the element already has
          // it. (This only matters for elements that have includesChildren = true).
          // If we are not counting child-element-focus as focused, make sure that the event target is the
          // monitored element itself.
          if (!this._elementInfo.get(element).checkChildren && element !== event.target) {
              return;
          }
          // If we couldn't detect a cause for the focus event, it's due to one of three reasons:
          // 1) The window has just regained focus, in which case we want to restore the focused state of
          //    the element from before the window blurred.
          // 2) It was caused by a touch event, in which case we mark the origin as 'touch'.
          // 3) The element was programmatically focused, in which case we should mark the origin as
          //    'program'.
          if (!this._origin) {
              if (this._windowFocused && this._lastFocusOrigin) {
                  this._origin = this._lastFocusOrigin;
              }
              else if (this._wasCausedByTouch(event)) {
                  this._origin = 'touch';
              }
              else {
                  this._origin = 'program';
              }
          }
          this._setClasses(element, this._origin);
          this._elementInfo.get(element).subject.next(this._origin);
          this._lastFocusOrigin = this._origin;
          this._origin = null;
      };
      /**
       * Handles blur events on a registered element.
       * @param event The blur event.
       * @param element The monitored element.
       */
      FocusOriginMonitor.prototype._onBlur = function (event, element) {
          // If we are counting child-element-focus as focused, make sure that we aren't just blurring in
          // order to focus another child of the monitored element.
          if (this._elementInfo.get(element).checkChildren && event.relatedTarget instanceof Node &&
              element.contains(event.relatedTarget)) {
              return;
          }
          this._setClasses(element, null);
          this._elementInfo.get(element).subject.next(null);
      };
      return FocusOriginMonitor;
  }());
  FocusOriginMonitor = __decorate([
      Injectable(),
      __metadata("design:paramtypes", [NgZone])
  ], FocusOriginMonitor);
  export { FocusOriginMonitor };
  /**
   * Directive that determines how a particular element was focused (via keyboard, mouse, touch, or
   * programmatically) and adds corresponding classes to the element.
   *
   * There are two variants of this directive:
   * 1) cdkMonitorElementFocus: does not consider an element to be focused if one of its children is
   *    focused.
   * 2) cdkMonitorSubtreeFocus: considers an element focused if it or any of its children are focused.
   */
  var CdkMonitorFocus = (function () {
      function CdkMonitorFocus(_elementRef, _focusOriginMonitor, renderer) {
          var _this = this;
          this._elementRef = _elementRef;
          this._focusOriginMonitor = _focusOriginMonitor;
          this.cdkFocusChange = new EventEmitter();
          this._focusOriginMonitor.monitor(this._elementRef.nativeElement, renderer, this._elementRef.nativeElement.hasAttribute('cdkMonitorSubtreeFocus'))
              .subscribe(function (origin) { return _this.cdkFocusChange.emit(origin); });
      }
      CdkMonitorFocus.prototype.ngOnDestroy = function () {
          this._focusOriginMonitor.unmonitor(this._elementRef.nativeElement);
      };
      return CdkMonitorFocus;
  }());
  __decorate([
      Output(),
      __metadata("design:type", Object)
  ], CdkMonitorFocus.prototype, "cdkFocusChange", void 0);
  CdkMonitorFocus = __decorate([
      Directive({
          selector: '[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]',
      }),
      __metadata("design:paramtypes", [ElementRef, FocusOriginMonitor,
          Renderer])
  ], CdkMonitorFocus);
  export { CdkMonitorFocus };
  export function FOCUS_ORIGIN_MONITOR_PROVIDER_FACTORY(parentDispatcher, ngZone) {
      return parentDispatcher || new FocusOriginMonitor(ngZone);
  }
  export var FOCUS_ORIGIN_MONITOR_PROVIDER = {
      // If there is already a FocusOriginMonitor available, use that. Otherwise, provide a new one.
      provide: FocusOriginMonitor,
      deps: [[new Optional(), new SkipSelf(), FocusOriginMonitor], NgZone],
      useFactory: FOCUS_ORIGIN_MONITOR_PROVIDER_FACTORY
  };
  //# sourceMappingURL=focus-origin-monitor.js.map