Skip to content

Commit

Permalink
feat(menu): Allow menu-trigger to take a menu interface. (#1564)
Browse files Browse the repository at this point in the history
This should enable menus to be more easily extended for custom menu implementations.

Fixes #1560.
  • Loading branch information
trshafer authored and hansl committed Nov 1, 2016
1 parent a331a43 commit 96d196a
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 11 deletions.
5 changes: 3 additions & 2 deletions src/lib/menu/menu-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {MenuPositionX, MenuPositionY} from './menu-positions';
import {MdMenuInvalidPositionX, MdMenuInvalidPositionY} from './menu-errors';
import {MdMenuItem} from './menu-item';
import {ListKeyManager} from '../core/a11y/list-key-manager';
import {MdMenuPanel} from './menu-panel';

@Component({
moduleId: module.id,
Expand All @@ -26,7 +27,7 @@ import {ListKeyManager} from '../core/a11y/list-key-manager';
encapsulation: ViewEncapsulation.None,
exportAs: 'mdMenu'
})
export class MdMenu {
export class MdMenu implements MdMenuPanel {
private _keyManager: ListKeyManager;

// config object to be passed into the menu's ngClass
Expand Down Expand Up @@ -70,7 +71,7 @@ export class MdMenu {
* to focus the first item when the menu is opened by the ENTER key.
* TODO: internal
*/
_focusFirstItem() {
focusFirstItem() {
// The menu always opens with the first item focused.
this.items.first.focus();
this._keyManager.focusedItemIndex = 0;
Expand Down
10 changes: 10 additions & 0 deletions src/lib/menu/menu-panel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {EventEmitter, TemplateRef} from '@angular/core';
import {MenuPositionX, MenuPositionY} from './menu-positions';

export interface MdMenuPanel {
positionX: MenuPositionX;
positionY: MenuPositionY;
templateRef: TemplateRef<any>;
close: EventEmitter<void>;
focusFirstItem: () => void;
}
8 changes: 4 additions & 4 deletions src/lib/menu/menu-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
OnDestroy,
Renderer
} from '@angular/core';
import {MdMenu} from './menu-directive';
import {MdMenuPanel} from './menu-panel';
import {MdMenuMissingError} from './menu-errors';
import {
ENTER,
Expand Down Expand Up @@ -47,7 +47,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
// the first item of the list when the menu is opened via the keyboard
private _openedFromKeyboard: boolean = false;

@Input('md-menu-trigger-for') menu: MdMenu;
@Input('md-menu-trigger-for') menu: MdMenuPanel;
@Output() onMenuOpen = new EventEmitter<void>();
@Output() onMenuClose = new EventEmitter<void>();

Expand Down Expand Up @@ -120,7 +120,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
this._setIsMenuOpen(true);

if (this._openedFromKeyboard) {
this.menu._focusFirstItem();
this.menu.focusFirstItem();
}
};

Expand Down Expand Up @@ -148,7 +148,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
* md-menu-trigger-for. If not, an exception is thrown.
*/
private _checkMenu() {
if (!this.menu || !(this.menu instanceof MdMenu)) {
if (!this.menu) {
throw new MdMenuMissingError();
}
}
Expand Down
65 changes: 60 additions & 5 deletions src/lib/menu/menu.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import {TestBed, async} from '@angular/core/testing';
import {Component, ViewChild} from '@angular/core';
import {MdMenuModule, MdMenuTrigger} from './menu';
import {
Component,
EventEmitter,
Output,
TemplateRef,
ViewChild
} from '@angular/core';
import {
MdMenuModule,
MdMenuTrigger,
MdMenuPanel,
MenuPositionX,
MenuPositionY
} from './menu';
import {OverlayContainer} from '../core/overlay/overlay-container';


Expand All @@ -10,7 +22,7 @@ describe('MdMenu', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdMenuModule.forRoot()],
declarations: [SimpleMenu],
declarations: [CustomMenuPanel, CustomMenu, SimpleMenu],
providers: [
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
Expand All @@ -30,7 +42,7 @@ describe('MdMenu', () => {
fixture.componentInstance.trigger.openMenu();
fixture.componentInstance.trigger.openMenu();

expect(overlayContainerElement.textContent.trim()).toBe('Content');
expect(overlayContainerElement.textContent.trim()).toBe('Simple Content');
}).not.toThrowError();
});

Expand All @@ -46,16 +58,59 @@ describe('MdMenu', () => {
expect(overlayContainerElement.textContent).toBe('');
});

it('should open a custom menu', () => {
const fixture = TestBed.createComponent(CustomMenu);
fixture.detectChanges();
expect(overlayContainerElement.textContent).toBe('');
expect(() => {
fixture.componentInstance.trigger.openMenu();
fixture.componentInstance.trigger.openMenu();

expect(overlayContainerElement.textContent).toContain('Custom Menu header');
expect(overlayContainerElement.textContent).toContain('Custom Content');
}).not.toThrowError();
});

});

@Component({
template: `
<button [md-menu-trigger-for]="menu">Toggle menu</button>
<md-menu #menu="mdMenu">
<button md-menu-item> Content </button>
<button md-menu-item> Simple Content </button>
</md-menu>
`
})
class SimpleMenu {
@ViewChild(MdMenuTrigger) trigger: MdMenuTrigger;
}

@Component({
selector: 'custom-menu',
template: `
<template>
Custom Menu header
<ng-content></ng-content>
</template>
`,
exportAs: 'mdCustomMenu'
})
class CustomMenuPanel implements MdMenuPanel {
positionX: MenuPositionX = 'after';
positionY: MenuPositionY = 'below';
@ViewChild(TemplateRef) templateRef: TemplateRef<any>;
@Output() close = new EventEmitter<void>();
focusFirstItem: () => void;
}

@Component({
template: `
<button [md-menu-trigger-for]="menu">Toggle menu</button>
<custom-menu #menu="mdCustomMenu">
<button md-menu-item> Custom Content </button>
</custom-menu>
`
})
class CustomMenu {
@ViewChild(MdMenuTrigger) trigger: MdMenuTrigger;
}
2 changes: 2 additions & 0 deletions src/lib/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {MdMenuTrigger} from './menu-trigger';
export {MdMenu} from './menu-directive';
export {MdMenuItem} from './menu-item';
export {MdMenuTrigger} from './menu-trigger';
export {MdMenuPanel} from './menu-panel';
export {MenuPositionX, MenuPositionY} from './menu-positions';


@NgModule({
Expand Down

0 comments on commit 96d196a

Please sign in to comment.