-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmenu-trigger.js
246 lines (245 loc) · 10.7 KB
/
menu-trigger.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
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);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { Directive, ElementRef, EventEmitter, Input, Optional, Output, Renderer, ViewContainerRef } from '@angular/core';
import { MdMenuMissingError } from './menu-errors';
import { isFakeMousedownFromScreenReader, Dir, Overlay, OverlayState, TemplatePortal } from '../core';
/**
* This directive is intended to be used in conjunction with an md-menu tag. It is
* responsible for toggling the display of the provided menu instance.
*/
export var MdMenuTrigger = (function () {
function MdMenuTrigger(_overlay, _element, _viewContainerRef, _renderer, _dir) {
this._overlay = _overlay;
this._element = _element;
this._viewContainerRef = _viewContainerRef;
this._renderer = _renderer;
this._dir = _dir;
this._menuOpen = false;
// tracking input type is necessary so it's possible to only auto-focus
// the first item of the list when the menu is opened via the keyboard
this._openedByMouse = false;
/** Event emitted when the associated menu is opened. */
this.onMenuOpen = new EventEmitter();
/** Event emitted when the associated menu is closed. */
this.onMenuClose = new EventEmitter();
}
Object.defineProperty(MdMenuTrigger.prototype, "_deprecatedMenuTriggerFor", {
/** @deprecated */
get: function () { return this.menu; },
set: function (v) { this.menu = v; },
enumerable: true,
configurable: true
});
MdMenuTrigger.prototype.ngAfterViewInit = function () {
var _this = this;
this._checkMenu();
this.menu.close.subscribe(function () { return _this.closeMenu(); });
};
MdMenuTrigger.prototype.ngOnDestroy = function () { this.destroyMenu(); };
Object.defineProperty(MdMenuTrigger.prototype, "menuOpen", {
/** Whether the menu is open. */
get: function () { return this._menuOpen; },
enumerable: true,
configurable: true
});
/** Toggles the menu between the open and closed states. */
MdMenuTrigger.prototype.toggleMenu = function () {
return this._menuOpen ? this.closeMenu() : this.openMenu();
};
/** Opens the menu. */
MdMenuTrigger.prototype.openMenu = function () {
if (!this._menuOpen) {
this._createOverlay();
this._overlayRef.attach(this._portal);
this._subscribeToBackdrop();
this._initMenu();
}
};
/** Closes the menu. */
MdMenuTrigger.prototype.closeMenu = function () {
if (this._overlayRef) {
this._overlayRef.detach();
this._backdropSubscription.unsubscribe();
this._resetMenu();
}
};
/** Removes the menu from the DOM. */
MdMenuTrigger.prototype.destroyMenu = function () {
if (this._overlayRef) {
this._overlayRef.dispose();
this._overlayRef = null;
this._cleanUpSubscriptions();
}
};
/** Focuses the menu trigger. */
MdMenuTrigger.prototype.focus = function () {
this._renderer.invokeElementMethod(this._element.nativeElement, 'focus');
};
Object.defineProperty(MdMenuTrigger.prototype, "dir", {
/** The text direction of the containing app. */
get: function () {
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
},
enumerable: true,
configurable: true
});
/**
* This method ensures that the menu closes when the overlay backdrop is clicked.
* We do not use first() here because doing so would not catch clicks from within
* the menu, and it would fail to unsubscribe properly. Instead, we unsubscribe
* explicitly when the menu is closed or destroyed.
*/
MdMenuTrigger.prototype._subscribeToBackdrop = function () {
var _this = this;
this._backdropSubscription = this._overlayRef.backdropClick().subscribe(function () {
_this.closeMenu();
});
};
/**
* This method sets the menu state to open and focuses the first item if
* the menu was opened via the keyboard.
*/
MdMenuTrigger.prototype._initMenu = function () {
this._setIsMenuOpen(true);
// Should only set focus if opened via the keyboard, so keyboard users can
// can easily navigate menu items. According to spec, mouse users should not
// see the focus style.
if (!this._openedByMouse) {
this.menu.focusFirstItem();
}
};
;
/**
* This method resets the menu when it's closed, most importantly restoring
* focus to the menu trigger if the menu was opened via the keyboard.
*/
MdMenuTrigger.prototype._resetMenu = function () {
this._setIsMenuOpen(false);
// Focus only needs to be reset to the host element if the menu was opened
// by the keyboard and manually shifted to the first menu item.
if (!this._openedByMouse) {
this.focus();
}
this._openedByMouse = false;
};
// set state rather than toggle to support triggers sharing a menu
MdMenuTrigger.prototype._setIsMenuOpen = function (isOpen) {
this._menuOpen = isOpen;
this._menuOpen ? this.onMenuOpen.emit() : this.onMenuClose.emit();
};
/**
* This method checks that a valid instance of MdMenu has been passed into
* mdMenuTriggerFor. If not, an exception is thrown.
*/
MdMenuTrigger.prototype._checkMenu = function () {
if (!this.menu) {
throw new MdMenuMissingError();
}
};
/**
* This method creates the overlay from the provided menu's template and saves its
* OverlayRef so that it can be attached to the DOM when openMenu is called.
*/
MdMenuTrigger.prototype._createOverlay = function () {
if (!this._overlayRef) {
this._portal = new TemplatePortal(this.menu.templateRef, this._viewContainerRef);
var config = this._getOverlayConfig();
this._subscribeToPositions(config.positionStrategy);
this._overlayRef = this._overlay.create(config);
}
};
/**
* This method builds the configuration object needed to create the overlay, the OverlayState.
* @returns OverlayState
*/
MdMenuTrigger.prototype._getOverlayConfig = function () {
var overlayState = new OverlayState();
overlayState.positionStrategy = this._getPosition()
.withDirection(this.dir);
overlayState.hasBackdrop = true;
overlayState.backdropClass = 'cdk-overlay-transparent-backdrop';
overlayState.direction = this.dir;
return overlayState;
};
/**
* Listens to changes in the position of the overlay and sets the correct classes
* on the menu based on the new position. This ensures the animation origin is always
* correct, even if a fallback position is used for the overlay.
*/
MdMenuTrigger.prototype._subscribeToPositions = function (position) {
var _this = this;
this._positionSubscription = position.onPositionChange.subscribe(function (change) {
var posX = change.connectionPair.originX === 'start' ? 'after' : 'before';
var posY = change.connectionPair.originY === 'top' ? 'below' : 'above';
_this.menu.setPositionClasses(posX, posY);
});
};
/**
* This method builds the position strategy for the overlay, so the menu is properly connected
* to the trigger.
* @returns ConnectedPositionStrategy
*/
MdMenuTrigger.prototype._getPosition = function () {
var _a = this.menu.positionX === 'before' ? ['end', 'start'] : ['start', 'end'], posX = _a[0], fallbackX = _a[1];
var _b = this.menu.positionY === 'above' ? ['bottom', 'top'] : ['top', 'bottom'], posY = _b[0], fallbackY = _b[1];
return this._overlay.position()
.connectedTo(this._element, { originX: posX, originY: posY }, { overlayX: posX, overlayY: posY })
.withFallbackPosition({ originX: fallbackX, originY: posY }, { overlayX: fallbackX, overlayY: posY })
.withFallbackPosition({ originX: posX, originY: fallbackY }, { overlayX: posX, overlayY: fallbackY })
.withFallbackPosition({ originX: fallbackX, originY: fallbackY }, { overlayX: fallbackX, overlayY: fallbackY });
};
MdMenuTrigger.prototype._cleanUpSubscriptions = function () {
if (this._backdropSubscription) {
this._backdropSubscription.unsubscribe();
}
if (this._positionSubscription) {
this._positionSubscription.unsubscribe();
}
};
MdMenuTrigger.prototype._handleMousedown = function (event) {
if (!isFakeMousedownFromScreenReader(event)) {
this._openedByMouse = true;
}
};
__decorate([
Input('md-menu-trigger-for'),
__metadata('design:type', Object)
], MdMenuTrigger.prototype, "_deprecatedMenuTriggerFor", null);
__decorate([
Input('mdMenuTriggerFor'),
__metadata('design:type', Object)
], MdMenuTrigger.prototype, "menu", void 0);
__decorate([
Output(),
__metadata('design:type', Object)
], MdMenuTrigger.prototype, "onMenuOpen", void 0);
__decorate([
Output(),
__metadata('design:type', Object)
], MdMenuTrigger.prototype, "onMenuClose", void 0);
MdMenuTrigger = __decorate([
Directive({
selector: '[md-menu-trigger-for], [mat-menu-trigger-for], [mdMenuTriggerFor]',
host: {
'aria-haspopup': 'true',
'(mousedown)': '_handleMousedown($event)',
'(click)': 'toggleMenu()',
},
exportAs: 'mdMenuTrigger'
}),
__param(4, Optional()),
__metadata('design:paramtypes', [Overlay, ElementRef, ViewContainerRef, Renderer, Dir])
], MdMenuTrigger);
return MdMenuTrigger;
}());
//# sourceMappingURL=menu-trigger.js.map