feat(directionality): a provider to get directionality (#4044)

- Looks at the `html` and `body` elements for `dir` attribute and sets the Directionality service value to it
- Whenever someone would try to inject Directionality - if there's a Dir directive up the dom tree it would be provided

fixes #3600
This commit is contained in:
Elad Bezalel
2017-06-20 02:30:41 +03:00
committed by Jeremy Elbourn
parent c220bb5260
commit 61d979e66e
33 changed files with 361 additions and 148 deletions
+3 -2
View File
@@ -28,7 +28,7 @@ import {ConnectedPositionStrategy} from '../core/overlay/position/connected-posi
import {Observable} from 'rxjs/Observable';
import {MdOptionSelectionChange, MdOption} from '../core/option/option';
import {ENTER, UP_ARROW, DOWN_ARROW, ESCAPE} from '../core/keyboard/keycodes';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {MdInputContainer} from '../input/input-container';
import {Subscription} from 'rxjs/Subscription';
import 'rxjs/add/observable/merge';
@@ -120,8 +120,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
constructor(private _element: ElementRef, private _overlay: Overlay,
private _viewContainerRef: ViewContainerRef,
private _zone: NgZone,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir: Dir, private _zone: NgZone,
@Optional() private _dir: Directionality,
@Optional() @Host() private _inputContainer: MdInputContainer,
@Optional() @Inject(DOCUMENT) private _document: any) {}
+3 -3
View File
@@ -19,7 +19,7 @@ import {
} from './index';
import {OverlayContainer} from '../core/overlay/overlay-container';
import {MdInputModule} from '../input/index';
import {Dir, LayoutDirection} from '../core/rtl/dir';
import {Directionality, Direction} from '../core/bidi/index';
import {Subscription} from 'rxjs/Subscription';
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW, ESCAPE} from '../core/keyboard/keycodes';
import {MdOption} from '../core/option/option';
@@ -35,7 +35,7 @@ import 'rxjs/add/operator/map';
describe('MdAutocomplete', () => {
let overlayContainerElement: HTMLElement;
let dir: LayoutDirection;
let dir: Direction;
let scrolledSubject = new Subject();
beforeEach(async(() => {
@@ -70,7 +70,7 @@ describe('MdAutocomplete', () => {
return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => ({value: dir})},
{provide: Directionality, useFactory: () => ({value: dir})},
{provide: ScrollDispatcher, useFactory: () => {
return {scrolled: (_delay: number, callback: () => any) => {
return scrolledSubject.asObservable().subscribe(callback);
+66
View File
@@ -0,0 +1,66 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
Directive,
HostBinding,
Output,
Input,
EventEmitter
} from '@angular/core';
import {Direction, Directionality} from './directionality';
/**
* Directive to listen for changes of direction of part of the DOM.
*
* Would provide itself in case a component looks for the Directionality service
*/
@Directive({
selector: '[dir]',
// TODO(hansl): maybe `$implicit` isn't the best option here, but for now that's the best we got.
exportAs: '$implicit',
providers: [
{provide: Directionality, useExisting: Dir}
]
})
export class Dir implements Directionality {
/** Layout direction of the element. */
_dir: Direction = 'ltr';
/** Whether the `value` has been set to its initial value. */
private _isInitialized: boolean = false;
/** Event emitted when the direction changes. */
@Output('dirChange') change = new EventEmitter<void>();
/** @docs-private */
@HostBinding('attr.dir')
@Input('dir')
get dir(): Direction {
return this._dir;
}
set dir(v: Direction) {
let old = this._dir;
this._dir = v;
if (old !== this._dir && this._isInitialized) {
this.change.emit();
}
}
/** Current layout direction of the element. */
get value(): Direction { return this.dir; }
set value(v: Direction) { this.dir = v; }
/** Initialize once default value has been set. */
ngAfterContentInit() {
this._isInitialized = true;
}
}
+104
View File
@@ -0,0 +1,104 @@
import {async, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {Component} from '@angular/core';
import {By} from '@angular/platform-browser';
import {BidiModule, Directionality, DIR_DOCUMENT} from './index';
describe('Directionality', () => {
let fakeDocument: FakeDocument;
beforeEach(async(() => {
fakeDocument = {body: {}, documentElement: {}};
TestBed.configureTestingModule({
imports: [BidiModule],
declarations: [ElementWithDir, InjectsDirectionality],
providers: [{provide: DIR_DOCUMENT, useFactory: () => fakeDocument}],
}).compileComponents();
}));
describe('Service', () => {
it('should read dir from the html element if not specified on the body', () => {
fakeDocument.documentElement.dir = 'rtl';
let fixture = TestBed.createComponent(InjectsDirectionality);
let testComponent = fixture.debugElement.componentInstance;
expect(testComponent.dir.value).toBe('rtl');
});
it('should read dir from the body even it is also specified on the html element', () => {
fakeDocument.documentElement.dir = 'ltr';
fakeDocument.body.dir = 'rtl';
let fixture = TestBed.createComponent(InjectsDirectionality);
let testComponent = fixture.debugElement.componentInstance;
expect(testComponent.dir.value).toBe('rtl');
});
it('should default to ltr if nothing is specified on either body or the html element', () => {
let fixture = TestBed.createComponent(InjectsDirectionality);
let testComponent = fixture.debugElement.componentInstance;
expect(testComponent.dir.value).toBe('ltr');
});
});
describe('Dir directive', () => {
it('should provide itself as Directionality', () => {
let fixture = TestBed.createComponent(ElementWithDir);
const injectedDirectionality =
fixture.debugElement.query(By.directive(InjectsDirectionality)).componentInstance.dir;
fixture.detectChanges();
expect(injectedDirectionality.value).toBe('rtl');
});
it('should emit a change event when the value changes', fakeAsync(() => {
let fixture = TestBed.createComponent(ElementWithDir);
const injectedDirectionality =
fixture.debugElement.query(By.directive(InjectsDirectionality)).componentInstance.dir;
fixture.detectChanges();
expect(injectedDirectionality.value).toBe('rtl');
expect(fixture.componentInstance.changeCount).toBe(0);
fixture.componentInstance.direction = 'ltr';
fixture.detectChanges();
tick();
expect(injectedDirectionality.value).toBe('ltr');
expect(fixture.componentInstance.changeCount).toBe(1);
}));
});
});
@Component({
template: `
<div [dir]="direction" (dirChange)="changeCount= changeCount + 1">
<injects-directionality></injects-directionality>
</div>
`
})
class ElementWithDir {
direction = 'rtl';
changeCount = 0;
}
/** Test component with Dir directive. */
@Component({
selector: 'injects-directionality',
template: `<div></div>`
})
class InjectsDirectionality {
constructor(public dir: Directionality) { }
}
interface FakeDocument {
documentElement: {dir?: string};
body: {dir?: string};
}
+64
View File
@@ -0,0 +1,64 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
EventEmitter,
Injectable,
Optional,
SkipSelf,
Inject,
InjectionToken,
} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
export type Direction = 'ltr' | 'rtl';
/**
* Injection token used to inject the document into Directionality.
* This is used so that the value can be faked in tests.
*
* We can't use the real document in tests because changing the real `dir` causes geometry-based
* tests in Safari to fail.
*
* We also can't re-provide the DOCUMENT token from platform-brower because the unit tests
* themselves use things like `querySelector` in test code.
*/
export const DIR_DOCUMENT = new InjectionToken<Document>('md-dir-doc');
/**
* The directionality (LTR / RTL) context for the application (or a subtree of it).
* Exposes the current direction and a stream of direction changes.
*/
@Injectable()
export class Directionality {
value: Direction = 'ltr';
change = new EventEmitter<void>();
constructor(@Optional() @Inject(DIR_DOCUMENT) _document?: any) {
if (typeof _document === 'object' && !!_document) {
// TODO: handle 'auto' value -
// We still need to account for dir="auto".
// It looks like HTMLElemenet.dir is also "auto" when that's set to the attribute,
// but getComputedStyle return either "ltr" or "rtl". avoiding getComputedStyle for now
// though, we're already calling it for the theming check.
this.value = (_document.body.dir || _document.documentElement.dir || 'ltr') as Direction;
}
}
}
export function DIRECTIONALITY_PROVIDER_FACTORY(parentDirectionality, _document) {
return parentDirectionality || new Directionality(_document);
}
export const DIRECTIONALITY_PROVIDER = {
// If there is already a Directionality available, use that. Otherwise, provide a new one.
provide: Directionality,
deps: [[new Optional(), new SkipSelf(), Directionality], [new Optional(), DOCUMENT]],
useFactory: DIRECTIONALITY_PROVIDER_FACTORY
};
+31
View File
@@ -0,0 +1,31 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgModule} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
import {Dir} from './dir';
import {DIR_DOCUMENT, Directionality, DIRECTIONALITY_PROVIDER} from './directionality';
export {
Directionality,
DIRECTIONALITY_PROVIDER,
DIR_DOCUMENT,
Direction,
} from './directionality';
export {Dir} from './dir';
@NgModule({
exports: [Dir],
declarations: [Dir],
providers: [
{provide: DIR_DOCUMENT, useExisting: DOCUMENT},
Directionality,
]
})
export class BidiModule { }
@@ -9,6 +9,7 @@
import {NgModule, InjectionToken, Optional, Inject, isDevMode} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
import {CompatibilityModule} from '../compatibility/compatibility';
import {BidiModule} from '../bidi/index';
/** Injection token that configures whether the Material sanity checks are enabled. */
@@ -22,8 +23,8 @@ export const MATERIAL_SANITY_CHECKS = new InjectionToken<boolean>('md-sanity-che
* This module should be imported to each top-level component module (e.g., MdTabsModule).
*/
@NgModule({
imports: [CompatibilityModule],
exports: [CompatibilityModule],
imports: [CompatibilityModule, BidiModule],
exports: [CompatibilityModule, BidiModule],
providers: [{
provide: MATERIAL_SANITY_CHECKS, useValue: true,
}],
+4 -4
View File
@@ -8,7 +8,7 @@
import {NgModule} from '@angular/core';
import {MdLineModule} from './line/line';
import {RtlModule} from './rtl/dir';
import {BidiModule} from './bidi/index';
import {ObserveContentModule} from './observe-content/observe-content';
import {MdOptionModule} from './option/index';
import {PortalModule} from './portal/portal-directives';
@@ -19,7 +19,7 @@ import {MdRippleModule} from './ripple/index';
// RTL
export {Dir, LayoutDirection, RtlModule} from './rtl/dir';
export {Dir, Direction, Directionality, BidiModule} from './bidi/index';
// Mutation Observer
export {ObserveContentModule, ObserveContent} from './observe-content/observe-content';
@@ -121,7 +121,7 @@ export {
@NgModule({
imports: [
MdLineModule,
RtlModule,
BidiModule,
MdRippleModule,
ObserveContentModule,
PortalModule,
@@ -132,7 +132,7 @@ export {
],
exports: [
MdLineModule,
RtlModule,
BidiModule,
MdRippleModule,
ObserveContentModule,
PortalModule,
@@ -5,7 +5,7 @@ import {ConnectedOverlayDirective, OverlayModule, OverlayOrigin} from './overlay
import {OverlayContainer} from './overlay-container';
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
import {ConnectedOverlayPositionChange} from './position/connected-position';
import {Dir} from '../rtl/dir';
import {Directionality} from '../bidi/index';
import {dispatchKeyboardEvent} from '../testing/dispatch-events';
import {ESCAPE} from '../keyboard/keycodes';
@@ -24,7 +24,7 @@ describe('Overlay directives', () => {
overlayContainerElement = document.createElement('div');
return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => {
{provide: Directionality, useFactory: () => {
return dir = { value: 'ltr' };
}}
],
+3 -3
View File
@@ -31,7 +31,7 @@ import {
} from './position/connected-position';
import {PortalModule} from '../portal/portal-directives';
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
import {Dir, LayoutDirection} from '../rtl/dir';
import {Directionality, Direction} from '../bidi/index';
import {Scrollable} from './scroll/scrollable';
import {ScrollStrategy} from './scroll/scroll-strategy';
import {coerceBooleanProperty} from '../coercion/boolean-property';
@@ -165,7 +165,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
private _renderer: Renderer2,
templateRef: TemplateRef<any>,
viewContainerRef: ViewContainerRef,
@Optional() private _dir: Dir) {
@Optional() private _dir: Directionality) {
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
}
@@ -175,7 +175,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
}
/** The element's layout direction. */
get dir(): LayoutDirection {
get dir(): Direction {
return this._dir ? this._dir.value : 'ltr';
}
+2 -2
View File
@@ -7,7 +7,7 @@
*/
import {PositionStrategy} from './position/position-strategy';
import {LayoutDirection} from '../rtl/dir';
import {Direction} from '../bidi/index';
import {ScrollStrategy} from './scroll/scroll-strategy';
@@ -44,7 +44,7 @@ export class OverlayState {
minHeight: number | string;
/** The direction of the text in the overlay panel. */
direction: LayoutDirection = 'ltr';
direction: Direction = 'ltr';
// TODO(jelbourn): configuration still to add
// - focus trap
-61
View File
@@ -1,61 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
NgModule,
Directive,
HostBinding,
Output,
Input,
EventEmitter
} from '@angular/core';
export type LayoutDirection = 'ltr' | 'rtl';
/**
* Directive to listen for changes of direction of part of the DOM.
*
* Applications should use this directive instead of the native attribute so that Material
* components can listen on changes of direction.
*/
@Directive({
selector: '[dir]',
// TODO(hansl): maybe `$implicit` isn't the best option here, but for now that's the best we got.
exportAs: '$implicit'
})
export class Dir {
/** Layout direction of the element. */
@Input('dir') _dir: LayoutDirection = 'ltr';
/** Event emitted when the direction changes. */
@Output() dirChange = new EventEmitter<void>();
/** @docs-private */
@HostBinding('attr.dir')
get dir(): LayoutDirection {
return this._dir;
}
set dir(v: LayoutDirection) {
let old = this._dir;
this._dir = v;
if (old != this._dir) {
this.dirChange.emit();
}
}
/** Current layout direction of the element. */
get value(): LayoutDirection { return this.dir; }
set value(v: LayoutDirection) { this.dir = v; }
}
@NgModule({
exports: [Dir],
declarations: [Dir]
})
export class RtlModule {}
+2 -3
View File
@@ -27,7 +27,7 @@ import {Overlay} from '../core/overlay/overlay';
import {OverlayRef} from '../core/overlay/overlay-ref';
import {ComponentPortal} from '../core/portal/portal';
import {OverlayState} from '../core/overlay/overlay-state';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {MdDialog} from '../dialog/dialog';
import {MdDialogRef} from '../dialog/dialog-ref';
import {PositionStrategy} from '../core/overlay/position/position-strategy';
@@ -164,9 +164,8 @@ export class MdDatepicker<D> implements OnDestroy {
private _ngZone: NgZone,
private _viewContainerRef: ViewContainerRef,
@Optional() private _dateAdapter: DateAdapter<D>,
@Optional() private _dir: Dir,
@Optional() private _dir: Directionality,
@Optional() @Inject(DOCUMENT) private _document: any) {
if (!this._dateAdapter) {
throw createMissingDateImplError('DateAdapter');
}
+2 -2
View File
@@ -7,7 +7,7 @@
*/
import {ViewContainerRef} from '@angular/core';
import {LayoutDirection} from '../core';
import {Direction} from '../core';
/** Valid ARIA roles for a dialog element. */
export type DialogRole = 'dialog' | 'alertdialog';
@@ -61,7 +61,7 @@ export class MdDialogConfig {
data?: any = null;
/** Layout direction for the dialog's content. */
direction?: LayoutDirection = 'ltr';
direction?: Direction = 'ltr';
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
}
+2 -2
View File
@@ -21,7 +21,7 @@ import {
import {MdGridTile} from './grid-tile';
import {TileCoordinator} from './tile-coordinator';
import {TileStyler, FitTileStyler, RatioTileStyler, FixedTileStyler} from './tile-styler';
import {Dir} from '../core';
import {Directionality} from '../core';
import {
coerceToString,
coerceToNumber,
@@ -69,7 +69,7 @@ export class MdGridList implements OnInit, AfterContentChecked {
constructor(
private _renderer: Renderer2,
private _element: ElementRef,
@Optional() private _dir: Dir) {}
@Optional() private _dir: Directionality) {}
/** Amount of columns in the grid list. */
@Input()
+5 -4
View File
@@ -21,8 +21,8 @@ import {MdMenuPanel} from './menu-panel';
import {throwMdMenuMissingError} from './menu-errors';
import {
isFakeMousedownFromScreenReader,
Dir,
LayoutDirection,
Directionality,
Direction,
Overlay,
OverlayState,
OverlayRef,
@@ -86,7 +86,8 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
@Output() onMenuClose = new EventEmitter<void>();
constructor(private _overlay: Overlay, private _element: ElementRef,
private _viewContainerRef: ViewContainerRef, @Optional() private _dir: Dir) { }
private _viewContainerRef: ViewContainerRef,
@Optional() private _dir: Directionality) { }
ngAfterViewInit() {
this._checkMenu();
@@ -138,7 +139,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
}
/** The text direction of the containing app. */
get dir(): LayoutDirection {
get dir(): Direction {
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
}
+3 -5
View File
@@ -18,7 +18,7 @@ import {
MenuPositionY
} from './index';
import {OverlayContainer} from '../core/overlay/overlay-container';
import {Dir, LayoutDirection} from '../core/rtl/dir';
import {Directionality, Direction} from '../core/bidi/index';
import {extendObject} from '../core/util/object-extend';
import {ESCAPE} from '../core/keyboard/keycodes';
import {dispatchKeyboardEvent} from '../core/testing/dispatch-events';
@@ -26,7 +26,7 @@ import {dispatchKeyboardEvent} from '../core/testing/dispatch-events';
describe('MdMenu', () => {
let overlayContainerElement: HTMLElement;
let dir: LayoutDirection;
let dir: Direction;
beforeEach(async(() => {
dir = 'ltr';
@@ -44,9 +44,7 @@ describe('MdMenu', () => {
document.body.style.margin = '0';
return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => {
return {value: dir};
}}
{provide: Directionality, useFactory: () => ({value: dir})}
]
});
+3 -3
View File
@@ -12,10 +12,10 @@ import {
A11yModule,
MdCommonModule,
MdRippleModule,
BidiModule,
ObserveContentModule,
OverlayModule,
PortalModule,
RtlModule
PortalModule
} from './core/index';
import {MdButtonToggleModule} from './button-toggle/index';
@@ -76,7 +76,7 @@ const MATERIAL_MODULES = [
MdTooltipModule,
OverlayModule,
PortalModule,
RtlModule,
BidiModule,
StyleModule,
A11yModule,
PlatformModule,
+2 -2
View File
@@ -15,7 +15,7 @@ import {OverlayContainer} from '../core/overlay/overlay-container';
import {MdSelect} from './select';
import {getMdSelectDynamicMultipleError, getMdSelectNonArrayValueError} from './select-errors';
import {MdOption} from '../core/option/option';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {DOWN_ARROW, UP_ARROW, ENTER, SPACE, HOME, END, TAB} from '../core/keyboard/keycodes';
import {
ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule
@@ -78,7 +78,7 @@ describe('MdSelect', () => {
return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => dir = { value: 'ltr' }},
{provide: Directionality, useFactory: () => dir = { value: 'ltr' }},
{provide: ScrollDispatcher, useFactory: () => {
return {scrolled: (_delay: number, callback: () => any) => {
return scrolledSubject.asObservable().subscribe(callback);
+2 -2
View File
@@ -29,7 +29,7 @@ import {
import {MdOption, MdOptionSelectionChange, MdOptgroup} from '../core/option/index';
import {ENTER, SPACE, UP_ARROW, DOWN_ARROW, HOME, END} from '../core/keyboard/keycodes';
import {FocusKeyManager} from '../core/a11y/focus-key-manager';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
import {transformPlaceholder, transformPanel, fadeInContent} from './select-animations';
@@ -322,7 +322,7 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
private _changeDetectorRef: ChangeDetectorRef,
renderer: Renderer2,
elementRef: ElementRef,
@Optional() private _dir: Dir,
@Optional() private _dir: Directionality,
@Self() @Optional() public _control: NgControl,
@Attribute('tabindex') tabIndex: string,
@Optional() @Inject(MD_PLACEHOLDER_GLOBAL_OPTIONS) placeholderOptions: PlaceholderOptions) {
+3 -3
View File
@@ -22,7 +22,7 @@ import {
NgZone,
OnDestroy, Inject,
} from '@angular/core';
import {Dir, coerceBooleanProperty} from '../core';
import {Directionality, coerceBooleanProperty} from '../core';
import {FocusTrapFactory, FocusTrap} from '../core/a11y/focus-trap';
import {ESCAPE} from '../core/keyboard/keycodes';
import 'rxjs/add/operator/first';
@@ -365,12 +365,12 @@ export class MdSidenavContainer implements AfterContentInit {
/** Whether to enable open/close trantions. */
_enableTransitions = false;
constructor(@Optional() private _dir: Dir, private _element: ElementRef,
constructor(@Optional() private _dir: Directionality, private _element: ElementRef,
private _renderer: Renderer2, private _ngZone: NgZone) {
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
// properties to point to the proper start/end.
if (_dir != null) {
_dir.dirChange.subscribe(() => this._validateDrawers());
_dir.change.subscribe(() => this._validateDrawers());
}
}
+2 -2
View File
@@ -12,11 +12,11 @@ import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {MdCommonModule, GestureConfig, StyleModule} from '../core';
import {MdSlider} from './slider';
import {RtlModule} from '../core/rtl/dir';
import {BidiModule} from '../core/bidi/index';
@NgModule({
imports: [CommonModule, FormsModule, MdCommonModule, StyleModule, RtlModule],
imports: [CommonModule, FormsModule, MdCommonModule, StyleModule, BidiModule],
exports: [MdSlider, MdCommonModule],
declarations: [MdSlider],
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]
+2 -2
View File
@@ -4,7 +4,7 @@ import {Component, DebugElement} from '@angular/core';
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
import {MdSlider, MdSliderModule} from './index';
import {TestGestureConfig} from './test-gesture-config';
import {RtlModule} from '../core/rtl/dir';
import {BidiModule} from '../core/bidi/index';
import {
DOWN_ARROW,
END,
@@ -23,7 +23,7 @@ describe('MdSlider', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdSliderModule, ReactiveFormsModule, FormsModule, RtlModule],
imports: [MdSliderModule, ReactiveFormsModule, FormsModule, BidiModule],
declarations: [
StandardSlider,
DisabledSlider,
+3 -2
View File
@@ -20,7 +20,7 @@ import {
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {coerceBooleanProperty, coerceNumberProperty, HammerInput} from '../core';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {
DOWN_ARROW,
END,
@@ -390,7 +390,8 @@ export class MdSlider extends _MdSliderMixinBase
}
constructor(renderer: Renderer2, private _elementRef: ElementRef,
private _focusOriginMonitor: FocusOriginMonitor, @Optional() private _dir: Dir) {
private _focusOriginMonitor: FocusOriginMonitor,
@Optional() private _dir: Directionality) {
super();
this._focusOriginMonitor.monitor(this._elementRef.nativeElement, renderer, true)
.subscribe((origin: FocusOrigin) => this._isActive = !!origin && origin !== 'keyboard');
+2 -2
View File
@@ -7,7 +7,7 @@
*/
import {ViewContainerRef} from '@angular/core';
import {AriaLivePoliteness, LayoutDirection} from '../core';
import {AriaLivePoliteness, Direction} from '../core';
/**
* Configuration used when opening a snack-bar.
@@ -29,5 +29,5 @@ export class MdSnackBarConfig {
extraClasses?: string[];
/** Text layout direction for the snack bar. */
direction?: LayoutDirection = 'ltr';
direction?: Direction = 'ltr';
}
+4 -4
View File
@@ -1,7 +1,7 @@
import {async, ComponentFixture, TestBed, flushMicrotasks, fakeAsync} from '@angular/core/testing';
import {Component, ViewChild, TemplateRef, ViewContainerRef} from '@angular/core';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {LayoutDirection, Dir} from '../core/rtl/dir';
import {Direction, Directionality} from '../core/bidi/index';
import {TemplatePortal} from '../core/portal/portal';
import {MdTabBody} from './tab-body';
import {MdRippleModule} from '../core/ripple/index';
@@ -10,7 +10,7 @@ import {PortalModule} from '../core';
describe('MdTabBody', () => {
let dir: LayoutDirection = 'ltr';
let dir: Direction = 'ltr';
beforeEach(async(() => {
dir = 'ltr';
@@ -21,8 +21,8 @@ describe('MdTabBody', () => {
SimpleTabBodyApp,
],
providers: [
{ provide: Dir, useFactory: () => { return {value: dir}; }
}]
{provide: Directionality, useFactory: () => ({value: dir})}
]
});
TestBed.compileComponents();
+4 -3
View File
@@ -26,7 +26,7 @@ import {
transition,
AnimationEvent,
} from '@angular/animations';
import {TemplatePortal, PortalHostDirective, Dir, LayoutDirection} from '../core';
import {TemplatePortal, PortalHostDirective, Directionality, Direction} from '../core';
import 'rxjs/add/operator/map';
/**
@@ -124,7 +124,8 @@ export class MdTabBody implements OnInit, AfterViewChecked {
}
}
constructor(@Optional() private _dir: Dir, private _elementRef: ElementRef) { }
constructor(private _elementRef: ElementRef,
@Optional() private _dir: Directionality) { }
/**
* After initialized, check if the content is centered and has an origin. If so, set the
@@ -165,7 +166,7 @@ export class MdTabBody implements OnInit, AfterViewChecked {
}
/** The text direction of the containing app. */
_getLayoutDirection(): LayoutDirection {
_getLayoutDirection(): Direction {
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
}
+8 -10
View File
@@ -1,6 +1,6 @@
import {async, ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {Component, ViewChild, ViewContainerRef} from '@angular/core';
import {LayoutDirection, Dir} from '../core/rtl/dir';
import {Direction, Directionality} from '../core/bidi/index';
import {MdTabHeader} from './tab-header';
import {MdRippleModule} from '../core/ripple/index';
import {CommonModule} from '@angular/common';
@@ -17,8 +17,8 @@ import {By} from '@angular/platform-browser';
describe('MdTabHeader', () => {
let dir: LayoutDirection = 'ltr';
let dirChange = new Subject();
let dir: Direction = 'ltr';
let change = new Subject();
let fixture: ComponentFixture<SimpleTabHeaderApp>;
let appComponent: SimpleTabHeaderApp;
@@ -33,9 +33,7 @@ describe('MdTabHeader', () => {
SimpleTabHeaderApp,
],
providers: [
{provide: Dir, useFactory: () => {
return {value: dir, dirChange: dirChange.asObservable()};
}},
{provide: Directionality, useFactory: () => ({value: dir, change: change.asObservable()})},
{provide: ViewportRuler, useClass: FakeViewportRuler},
]
});
@@ -239,13 +237,13 @@ describe('MdTabHeader', () => {
it('should re-align the ink bar when the direction changes', () => {
fixture = TestBed.createComponent(SimpleTabHeaderApp);
fixture.detectChanges();
const inkBar = fixture.componentInstance.mdTabHeader._inkBar;
spyOn(inkBar, 'alignToElement');
dirChange.next();
fixture.detectChanges();
change.next();
fixture.detectChanges();
expect(inkBar.alignToElement).toHaveBeenCalled();
@@ -301,7 +299,7 @@ class SimpleTabHeaderApp {
focusedIndex: number;
disabledTabIndex = 1;
tabs: Tab[] = [{label: 'tab one'}, {label: 'tab one'}, {label: 'tab one'}, {label: 'tab one'}];
dir: LayoutDirection = 'ltr';
dir: Direction = 'ltr';
@ViewChild(MdTabHeader) mdTabHeader: MdTabHeader;
+11 -4
View File
@@ -22,7 +22,14 @@ import {
OnDestroy,
NgZone,
} from '@angular/core';
import {RIGHT_ARROW, LEFT_ARROW, ENTER, Dir, LayoutDirection, coerceBooleanProperty} from '../core';
import {
RIGHT_ARROW,
LEFT_ARROW,
ENTER,
Directionality,
Direction,
coerceBooleanProperty
} from '../core';
import {MdTabLabelWrapper} from './tab-label-wrapper';
import {MdInkBar} from './ink-bar';
import {Subscription} from 'rxjs/Subscription';
@@ -131,7 +138,7 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit, OnDes
constructor(
private _elementRef: ElementRef,
private _ngZone: NgZone,
@Optional() private _dir: Dir) { }
@Optional() private _dir: Directionality) { }
ngAfterContentChecked(): void {
// If the number of tab labels have changed, check if scrolling should be enabled
@@ -176,7 +183,7 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit, OnDes
*/
ngAfterContentInit() {
this._realignInkBar = this._ngZone.runOutsideAngular(() => {
let dirChange = this._dir ? this._dir.dirChange : Observable.of(null);
let dirChange = this._dir ? this._dir.change : Observable.of(null);
let resize = typeof window !== 'undefined' ?
Observable.fromEvent(window, 'resize').auditTime(10) :
Observable.of(null);
@@ -288,7 +295,7 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit, OnDes
}
/** The layout direction of the containing app. */
_getLayoutDirection(): LayoutDirection {
_getLayoutDirection(): Direction {
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
}
+6 -5
View File
@@ -6,12 +6,12 @@ import {By} from '@angular/platform-browser';
import {ViewportRuler} from '../../core/overlay/position/viewport-ruler';
import {FakeViewportRuler} from '../../core/overlay/position/fake-viewport-ruler';
import {dispatchFakeEvent, dispatchMouseEvent} from '../../core/testing/dispatch-events';
import {Dir, LayoutDirection} from '../../core/rtl/dir';
import {Direction, Directionality} from '../../core/bidi/index';
import {Subject} from 'rxjs/Subject';
describe('MdTabNavBar', () => {
let dir: LayoutDirection = 'ltr';
let dir: Direction = 'ltr';
let dirChange = new Subject();
beforeEach(async(() => {
@@ -22,9 +22,10 @@ describe('MdTabNavBar', () => {
TabLinkWithNgIf,
],
providers: [
{provide: Dir, useFactory: () => {
return {value: dir, dirChange: dirChange.asObservable()};
}},
{provide: Directionality, useFactory: () => ({
value: dir,
change: dirChange.asObservable()
})},
{provide: ViewportRuler, useClass: FakeViewportRuler},
]
});
+3 -3
View File
@@ -22,7 +22,7 @@ import {
import {MdInkBar} from '../ink-bar';
import {MdRipple} from '../../core/ripple/index';
import {ViewportRuler} from '../../core/overlay/position/viewport-ruler';
import {Dir, MD_RIPPLE_GLOBAL_OPTIONS, Platform, RippleGlobalOptions} from '../../core';
import {Directionality, MD_RIPPLE_GLOBAL_OPTIONS, Platform, RippleGlobalOptions} from '../../core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/auditTime';
import 'rxjs/add/operator/takeUntil';
@@ -51,7 +51,7 @@ export class MdTabNav implements AfterContentInit, OnDestroy {
@ViewChild(MdInkBar) _inkBar: MdInkBar;
constructor(@Optional() private _dir: Dir, private _ngZone: NgZone) { }
constructor(@Optional() private _dir: Directionality, private _ngZone: NgZone) { }
/** Notifies the component that the active link has been changed. */
updateActiveLink(element: ElementRef) {
@@ -61,7 +61,7 @@ export class MdTabNav implements AfterContentInit, OnDestroy {
ngAfterContentInit(): void {
this._ngZone.runOutsideAngular(() => {
let dirChange = this._dir ? this._dir.dirChange : Observable.of(null);
let dirChange = this._dir ? this._dir.change : Observable.of(null);
let resize = typeof window !== 'undefined' ?
Observable.fromEvent(window, 'resize').auditTime(10) :
Observable.of(null);
+3 -3
View File
@@ -17,7 +17,7 @@ import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {TooltipPosition, MdTooltip, MdTooltipModule, SCROLL_THROTTLE_MS} from './index';
import {OverlayContainer} from '../core';
import {Dir, LayoutDirection} from '../core/rtl/dir';
import {Directionality, Direction} from '../core/bidi/index';
import {OverlayModule} from '../core/overlay/overlay-directives';
import {Platform} from '../core/platform/platform';
import {Scrollable} from '../core/overlay/scroll/scrollable';
@@ -28,7 +28,7 @@ const initialTooltipMessage = 'initial tooltip message';
describe('MdTooltip', () => {
let overlayContainerElement: HTMLElement;
let dir: {value: LayoutDirection};
let dir: {value: Direction};
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -41,7 +41,7 @@ describe('MdTooltip', () => {
document.body.appendChild(overlayContainerElement);
return {getContainerElement: () => overlayContainerElement};
}},
{provide: Dir, useFactory: () => {
{provide: Directionality, useFactory: () => {
return dir = { value: 'ltr' };
}}
]
+4 -3
View File
@@ -37,7 +37,7 @@ import {
} from '../core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {Dir} from '../core/rtl/dir';
import {Directionality} from '../core/bidi/index';
import {Platform} from '../core/platform/index';
import 'rxjs/add/operator/first';
import {ScrollDispatcher} from '../core/overlay/scroll/scroll-dispatcher';
@@ -180,7 +180,7 @@ export class MdTooltip implements OnDestroy {
private _ngZone: NgZone,
private _renderer: Renderer2,
private _platform: Platform,
@Optional() private _dir: Dir) {
@Optional() private _dir: Directionality) {
// The mouse events shouldn't be bound on iOS devices, because
// they can prevent the first tap from firing its click event.
@@ -402,7 +402,8 @@ export class TooltipComponent {
/** Subject for notifying that the tooltip has been hidden from the view */
private _onHide: Subject<any> = new Subject();
constructor(@Optional() private _dir: Dir, private _changeDetectorRef: ChangeDetectorRef) {}
constructor(@Optional() private _dir: Directionality,
private _changeDetectorRef: ChangeDetectorRef) {}
/**
* Shows the tooltip with an animation originating from the provided origin