diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts
index ec35c947b74..afcc8e6d738 100644
--- a/src/demo-app/demo-app-module.ts
+++ b/src/demo-app/demo-app-module.ts
@@ -35,6 +35,7 @@ import {PortalDemo, ScienceJoke} from './portal/portal-demo';
import {MenuDemo} from './menu/menu-demo';
import {TabsDemo, SunnyTabContent, RainyTabContent, FoggyTabContent} from './tabs/tabs-demo';
import {ProjectionDemo, ProjectionTestComponent} from './projection/projection-demo';
+import {PlatformDemo} from './platform/platform-demo';
@NgModule({
imports: [
@@ -86,6 +87,7 @@ import {ProjectionDemo, ProjectionTestComponent} from './projection/projection-d
SunnyTabContent,
RainyTabContent,
FoggyTabContent,
+ PlatformDemo
],
entryComponents: [
DemoApp,
diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts
index 2b229a41405..005564a13c0 100644
--- a/src/demo-app/demo-app/demo-app.ts
+++ b/src/demo-app/demo-app/demo-app.ts
@@ -47,6 +47,7 @@ export class DemoApp {
{name: 'Snack Bar', route: 'snack-bar'},
{name: 'Tabs', route: 'tabs'},
{name: 'Toolbar', route: 'toolbar'},
- {name: 'Tooltip', route: 'tooltip'}
+ {name: 'Tooltip', route: 'tooltip'},
+ {name: 'Platform', route: 'platform'}
];
}
diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts
index 285be668b89..7cc7685eb22 100644
--- a/src/demo-app/demo-app/routes.ts
+++ b/src/demo-app/demo-app/routes.ts
@@ -30,6 +30,7 @@ import {TooltipDemo} from '../tooltip/tooltip-demo';
import {SnackBarDemo} from '../snack-bar/snack-bar-demo';
import {ProjectionDemo} from '../projection/projection-demo';
import {TABS_DEMO_ROUTES} from '../tabs/routes';
+import {PlatformDemo} from '../platform/platform-demo';
export const DEMO_APP_ROUTES: Routes = [
{path: '', component: Home},
@@ -62,4 +63,5 @@ export const DEMO_APP_ROUTES: Routes = [
{path: 'dialog', component: DialogDemo},
{path: 'tooltip', component: TooltipDemo},
{path: 'snack-bar', component: SnackBarDemo},
+ {path: 'platform', component: PlatformDemo}
];
diff --git a/src/demo-app/platform/platform-demo.ts b/src/demo-app/platform/platform-demo.ts
new file mode 100644
index 00000000000..c5b746a70fe
--- /dev/null
+++ b/src/demo-app/platform/platform-demo.ts
@@ -0,0 +1,17 @@
+import {Component} from '@angular/core';
+import {MdPlatform} from '@angular/material';
+
+@Component({
+ template: `
+
Is Android: {{ platform.ANDROID }}
+ Is iOS: {{ platform.IOS }}
+ Is Firefox: {{ platform.FIREFOX }}
+ Is Blink: {{ platform.BLINK }}
+ Is Webkit: {{ platform.WEBKIT }}
+ Is Trident: {{ platform.TRIDENT }}
+ Is Edge: {{ platform.EDGE }}
+ `
+})
+export class PlatformDemo {
+ constructor(public platform: MdPlatform) {}
+}
diff --git a/src/lib/core/a11y/focus-trap.spec.ts b/src/lib/core/a11y/focus-trap.spec.ts
index 0e225d8b665..86357817dfe 100644
--- a/src/lib/core/a11y/focus-trap.spec.ts
+++ b/src/lib/core/a11y/focus-trap.spec.ts
@@ -3,17 +3,21 @@ import {By} from '@angular/platform-browser';
import {Component} from '@angular/core';
import {FocusTrap} from './focus-trap';
import {InteractivityChecker} from './interactivity-checker';
+import {MdPlatform} from '../platform/platform';
describe('FocusTrap', () => {
+
describe('with default element', () => {
+
let fixture: ComponentFixture;
let focusTrapInstance: FocusTrap;
+ let platform: MdPlatform = new MdPlatform();
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FocusTrap, FocusTrapTestApp],
- providers: [InteractivityChecker]
+ providers: [InteractivityChecker, MdPlatform]
});
TestBed.compileComponents();
@@ -38,8 +42,11 @@ describe('FocusTrap', () => {
// focus event handler directly.
focusTrapInstance.focusLastTabbableElement();
+ // In iOS button elements are never tabbable, so the last element will be the input.
+ let lastElement = platform.IOS ? 'input' : 'button';
+
expect(document.activeElement.nodeName.toLowerCase())
- .toBe('button', 'Expected button element to be focused');
+ .toBe(lastElement, `Expected ${lastElement} element to be focused`);
});
});
@@ -50,7 +57,7 @@ describe('FocusTrap', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FocusTrap, FocusTrapTargetTestApp],
- providers: [InteractivityChecker]
+ providers: [InteractivityChecker, MdPlatform]
});
TestBed.compileComponents();
diff --git a/src/lib/core/a11y/index.ts b/src/lib/core/a11y/index.ts
index 70621bb45e9..0e285f77d60 100644
--- a/src/lib/core/a11y/index.ts
+++ b/src/lib/core/a11y/index.ts
@@ -2,10 +2,12 @@ import {NgModule, ModuleWithProviders} from '@angular/core';
import {FocusTrap} from './focus-trap';
import {MdLiveAnnouncer} from './live-announcer';
import {InteractivityChecker} from './interactivity-checker';
+import {PlatformModule} from '../platform/platform';
export const A11Y_PROVIDERS = [MdLiveAnnouncer, InteractivityChecker];
@NgModule({
+ imports: [PlatformModule],
declarations: [FocusTrap],
exports: [FocusTrap],
})
diff --git a/src/lib/core/a11y/interactivity-checker.spec.ts b/src/lib/core/a11y/interactivity-checker.spec.ts
index 648499781ae..ab707d66515 100644
--- a/src/lib/core/a11y/interactivity-checker.spec.ts
+++ b/src/lib/core/a11y/interactivity-checker.spec.ts
@@ -1,14 +1,17 @@
import {InteractivityChecker} from './interactivity-checker';
+import {MdPlatform} from '../platform/platform';
+import {async} from '@angular/core/testing';
describe('InteractivityChecker', () => {
let testContainerElement: HTMLElement;
let checker: InteractivityChecker;
+ let platform: MdPlatform = new MdPlatform();
beforeEach(() => {
testContainerElement = document.createElement('div');
document.body.appendChild(testContainerElement);
- checker = new InteractivityChecker();
+ checker = new InteractivityChecker(platform);
});
afterEach(() => {
@@ -234,52 +237,237 @@ describe('InteractivityChecker', () => {
});
});
- it('should return true for div and span with tabindex == 0', () => {
- let elements = createElements('div', 'span');
- elements.forEach(el => el.setAttribute('tabindex', '0'));
- appendElements(elements);
-
- elements.forEach(el => {
- expect(checker.isFocusable(el))
- .toBe(true, `Expected <${el.nodeName} tabindex="0"> to be focusable`);
- });
- });
});
describe('isTabbable', () => {
- it('should return true for native form controls and anchor without tabindex attribute', () => {
- let elements = createElements('input', 'textarea', 'select', 'button', 'a');
- appendElements(elements);
- elements.forEach(el => {
- expect(checker.isTabbable(el)).toBe(true, `Expected <${el.nodeName}> to be tabbable`);
+ it('should respect the tabindex for video elements with controls',
+ // Do not run for Blink, Firefox and iOS because those treat video elements
+ // with controls different and are covered in other tests.
+ runIf(!platform.BLINK && !platform.FIREFOX && !platform.IOS, () => {
+ let video = createFromTemplate('