UNPKG

md2

Version:

Angular2 based Material Design components, directives and services are Accordion, Autocomplete, Chips(Tags), Collapse, Colorpicker, Data Table, Datepicker, Dialog(Modal), Menu, Multiselect, Select, Tabs, Tags(Chips), Toast and Tooltip.

289 lines 14.3 kB
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, Renderer2, SkipSelf, } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { Platform } from '../platform/platform'; import 'rxjs/add/observable/of'; // 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, _platform) { var _this = this; this._ngZone = _ngZone; this._platform = _platform; /** 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; // Do nothing if we're not on the browser platform. if (!this._platform.isBrowser) { return Observable.of(); } // 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.stopMonitoring = 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 origin The focus origin. */ FocusOriginMonitor.prototype.focusVia = function (element, origin) { this._setOriginForCurrentEventQueue(origin); element.focus(); }; /** Register necessary event listeners on the document and window. */ FocusOriginMonitor.prototype._registerDocumentEvents = function () { var _this = this; // Do nothing if we're not on the browser platform. if (!this._platform.isBrowser) { return; } // Note: we listen to events in the capture phase so we can detect them even if the user stops // propagation. // 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; var toggleClass = function (className, shouldSet) { shouldSet ? renderer.addClass(element, className) : renderer.removeClass(element, className); }; toggleClass('cdk-focused', !!origin); toggleClass('cdk-touch-focused', origin === 'touch'); toggleClass('cdk-keyboard-focused', origin === 'keyboard'); toggleClass('cdk-mouse-focused', origin === 'mouse'); toggleClass('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, Platform]) ], 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.stopMonitoring(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, Renderer2]) ], CdkMonitorFocus); export { CdkMonitorFocus }; export function FOCUS_ORIGIN_MONITOR_PROVIDER_FACTORY(parentDispatcher, ngZone, platform) { return parentDispatcher || new FocusOriginMonitor(ngZone, platform); } 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, Platform], useFactory: FOCUS_ORIGIN_MONITOR_PROVIDER_FACTORY }; //# sourceMappingURL=focus-origin-monitor.js.map