Skip to content

Commit 1793720

Browse files
committed
feat(directionality): a provider to get the overall directionality
- 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
1 parent 21f8899 commit 1793720

27 files changed

+124
-126
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {ConnectedPositionStrategy} from '../core/overlay/position/connected-posi
1717
import {Observable} from 'rxjs/Observable';
1818
import {MdOptionSelectionChange, MdOption} from '../core/option/option';
1919
import {ENTER, UP_ARROW, DOWN_ARROW} from '../core/keyboard/keycodes';
20-
import {Dir} from '../core/rtl/dir';
20+
import {Directionality} from '../core/bidi/index';
2121
import {Subscription} from 'rxjs/Subscription';
2222
import {Subject} from 'rxjs/Subject';
2323
import 'rxjs/add/observable/merge';
@@ -101,7 +101,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
101101

102102
constructor(private _element: ElementRef, private _overlay: Overlay,
103103
private _viewContainerRef: ViewContainerRef,
104-
@Optional() private _dir: Dir, private _zone: NgZone,
104+
@Optional() private _dir: Directionality, private _zone: NgZone,
105105
@Optional() @Host() private _inputContainer: MdInputContainer) {}
106106

107107
ngOnDestroy() {

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
55
import {MdAutocompleteModule, MdAutocompleteTrigger} from './index';
66
import {OverlayContainer} from '../core/overlay/overlay-container';
77
import {MdInputModule} from '../input/index';
8-
import {Dir, LayoutDirection} from '../core/rtl/dir';
8+
import {Directionality, Direction} from '../core/bidi/index';
99
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
1010
import {Subscription} from 'rxjs/Subscription';
1111
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW} from '../core/keyboard/keycodes';
@@ -22,7 +22,7 @@ import 'rxjs/add/operator/map';
2222

2323
describe('MdAutocomplete', () => {
2424
let overlayContainerElement: HTMLElement;
25-
let dir: LayoutDirection;
25+
let dir: Direction;
2626

2727
beforeEach(async(() => {
2828
dir = 'ltr';
@@ -51,7 +51,7 @@ describe('MdAutocomplete', () => {
5151

5252
return {getContainerElement: () => overlayContainerElement};
5353
}},
54-
{provide: Dir, useFactory: () => {
54+
{provide: Directionality, useFactory: () => {
5555
return {value: dir};
5656
}},
5757
{provide: ViewportRuler, useClass: FakeViewportRuler}

src/lib/core/bidi/dir.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {
2+
Directive,
3+
HostBinding,
4+
Output,
5+
Input,
6+
EventEmitter
7+
} from '@angular/core';
8+
9+
import {Direction, Directionality} from './directionality';
10+
11+
/**
12+
* Directive to listen for changes of direction of part of the DOM.
13+
*
14+
* Would provide itself in case a component looks for the Directionality service
15+
*/
16+
@Directive({
17+
selector: '[dir]',
18+
// TODO(hansl): maybe `$implicit` isn't the best option here, but for now that's the best we got.
19+
exportAs: '$implicit',
20+
providers: [
21+
{provide: Directionality, useExisting: Dir}
22+
]
23+
})
24+
export class Dir implements Directionality {
25+
/** Layout direction of the element. */
26+
@Input('dir') _dir: Direction = 'ltr';
27+
28+
/** Event emitted when the direction changes. */
29+
@Output() change = new EventEmitter<void>();
30+
31+
/** @docs-private */
32+
@HostBinding('attr.dir')
33+
get dir(): Direction {
34+
return this._dir;
35+
}
36+
37+
set dir(v: Direction) {
38+
let old = this._dir;
39+
this._dir = v;
40+
if (old != this._dir) {
41+
this.change.emit();
42+
}
43+
}
44+
45+
/** Current layout direction of the element. */
46+
get value(): Direction { return this.dir; }
47+
set value(v: Direction) { this.dir = v; }
48+
}
49+

src/lib/core/bidi/directionality.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import { EventEmitter, Injectable, ModuleWithProviders, NgModule, Optional, SkipSelf} from '@angular/core';import {Dir} from './dir';export type Direction = 'ltr' | 'rtl';/** * 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: EventEmitter<void> = new EventEmitter<void>(); constructor() { if (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.getAttribute('dir') || document.documentElement.getAttribute('dir') || 'ltr') as Direction; } }}@NgModule({ exports: [Dir], declarations: [Dir], providers: [Directionality]})export class BidiModule { /** @deprecated */ static forRoot(): ModuleWithProviders { return { ngModule: BidiModule, providers: [DIRECTIONALITY_PROVIDER] }; }}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]], useFactory: function (parentDirectionality) { return parentDirectionality || new Directionality(); }};

src/lib/core/bidi/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export {
2+
Directionality,
3+
BidiModule,
4+
DIRECTIONALITY_PROVIDER,
5+
Direction
6+
} from './directionality';
7+
export {Dir} from './dir';

src/lib/core/core.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {NgModule, ModuleWithProviders} from '@angular/core';
22
import {MdLineModule} from './line/line';
3-
import {RtlModule} from './rtl/dir';
3+
import {BidiModule} from './bidi/index';
44
import {ObserveContentModule} from './observe-content/observe-content';
55
import {MdOptionModule} from './option/option';
66
import {PortalModule} from './portal/portal-directives';
@@ -11,7 +11,7 @@ import {MdRippleModule} from './ripple/index';
1111

1212

1313
// RTL
14-
export {Dir, LayoutDirection, RtlModule} from './rtl/dir';
14+
export {Dir, Direction, Directionality, BidiModule} from './bidi/index';
1515

1616
// Mutation Observer
1717
export {ObserveContentModule, ObserveContent} from './observe-content/observe-content';
@@ -117,7 +117,7 @@ export {CompatibilityModule, NoConflictStyleCompatibilityMode} from './compatibi
117117
@NgModule({
118118
imports: [
119119
MdLineModule,
120-
RtlModule,
120+
BidiModule,
121121
MdRippleModule,
122122
ObserveContentModule,
123123
PortalModule,
@@ -128,7 +128,7 @@ export {CompatibilityModule, NoConflictStyleCompatibilityMode} from './compatibi
128128
],
129129
exports: [
130130
MdLineModule,
131-
RtlModule,
131+
BidiModule,
132132
MdRippleModule,
133133
ObserveContentModule,
134134
PortalModule,

src/lib/core/overlay/overlay-directives.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {ConnectedOverlayDirective, OverlayModule} from './overlay-directives';
55
import {OverlayContainer} from './overlay-container';
66
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
77
import {ConnectedOverlayPositionChange} from './position/connected-position';
8-
import {Dir} from '../rtl/dir';
8+
import {Directionality} from '../bidi/index';
99

1010

1111
describe('Overlay directives', () => {
@@ -22,7 +22,7 @@ describe('Overlay directives', () => {
2222
overlayContainerElement = document.createElement('div');
2323
return {getContainerElement: () => overlayContainerElement};
2424
}},
25-
{provide: Dir, useFactory: () => {
25+
{provide: Directionality, useFactory: () => {
2626
return dir = { value: 'ltr' };
2727
}}
2828
],

src/lib/core/overlay/overlay-directives.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
import {PortalModule} from '../portal/portal-directives';
2323
import {ConnectedPositionStrategy} from './position/connected-position-strategy';
2424
import {Subscription} from 'rxjs/Subscription';
25-
import {Dir, LayoutDirection} from '../rtl/dir';
25+
import {Directionality, Direction} from '../bidi/index';
2626
import {Scrollable} from './scroll/scrollable';
2727
import {coerceBooleanProperty} from '../coercion/boolean-property';
2828

@@ -154,7 +154,7 @@ export class ConnectedOverlayDirective implements OnDestroy {
154154
private _overlay: Overlay,
155155
templateRef: TemplateRef<any>,
156156
viewContainerRef: ViewContainerRef,
157-
@Optional() private _dir: Dir) {
157+
@Optional() private _dir: Directionality) {
158158
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
159159
}
160160

@@ -164,7 +164,7 @@ export class ConnectedOverlayDirective implements OnDestroy {
164164
}
165165

166166
/** The element's layout direction. */
167-
get dir(): LayoutDirection {
167+
get dir(): Direction {
168168
return this._dir ? this._dir.value : 'ltr';
169169
}
170170

src/lib/core/overlay/overlay-state.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {PositionStrategy} from './position/position-strategy';
2-
import {LayoutDirection} from '../rtl/dir';
2+
import {Direction} from '../bidi/index';
33

44

55
/**
@@ -29,7 +29,7 @@ export class OverlayState {
2929
minHeight: number | string;
3030

3131
/** The direction of the text in the overlay panel. */
32-
direction: LayoutDirection = 'ltr';
32+
direction: Direction = 'ltr';
3333

3434
// TODO(jelbourn): configuration still to add
3535
// - focus trap

src/lib/core/rtl/dir.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/lib/grid-list/grid-list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {MdGridTile} from './grid-tile';
1414
import {TileCoordinator} from './tile-coordinator';
1515
import {TileStyler, FitTileStyler, RatioTileStyler, FixedTileStyler} from './tile-styler';
1616
import {MdGridListColsError} from './grid-list-errors';
17-
import {Dir} from '../core';
17+
import {Directionality} from '../core';
1818
import {
1919
coerceToString,
2020
coerceToNumber,
@@ -62,7 +62,7 @@ export class MdGridList implements OnInit, AfterContentChecked {
6262
constructor(
6363
private _renderer: Renderer,
6464
private _element: ElementRef,
65-
@Optional() private _dir: Dir) {}
65+
@Optional() private _dir: Directionality) {}
6666

6767
/** Amount of columns in the grid list. */
6868
@Input()

src/lib/menu/menu-trigger.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import {MdMenuPanel} from './menu-panel';
1414
import {MdMenuMissingError} from './menu-errors';
1515
import {
1616
isFakeMousedownFromScreenReader,
17-
Dir,
18-
LayoutDirection,
17+
Directionality,
18+
Direction,
1919
Overlay,
2020
OverlayState,
2121
OverlayRef,
@@ -80,7 +80,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
8080

8181
constructor(private _overlay: Overlay, private _element: ElementRef,
8282
private _viewContainerRef: ViewContainerRef, private _renderer: Renderer,
83-
@Optional() private _dir: Dir) {}
83+
@Optional() private _dir: Directionality) {}
8484

8585
ngAfterViewInit() {
8686
this._checkMenu();
@@ -132,7 +132,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
132132
}
133133

134134
/** The text direction of the containing app. */
135-
get dir(): LayoutDirection {
135+
get dir(): Direction {
136136
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
137137
}
138138

src/lib/menu/menu.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import {
1919
} from './index';
2020
import {OverlayContainer} from '../core/overlay/overlay-container';
2121
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
22-
import {Dir, LayoutDirection} from '../core/rtl/dir';
22+
import {Directionality, Direction} from '../core/bidi/index';
2323
import {extendObject} from '../core/util/object-extend';
2424

2525
describe('MdMenu', () => {
2626
let overlayContainerElement: HTMLElement;
27-
let dir: LayoutDirection;
27+
let dir: Direction;
2828

2929
beforeEach(async(() => {
3030
dir = 'ltr';
@@ -44,7 +44,7 @@ describe('MdMenu', () => {
4444
document.body.style.margin = '0';
4545
return {getContainerElement: () => overlayContainerElement};
4646
}},
47-
{provide: Dir, useFactory: () => {
47+
{provide: Directionality, useFactory: () => {
4848
return {value: dir};
4949
}},
5050
{provide: ViewportRuler, useClass: FakeViewportRuler}

src/lib/module.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {NgModule, ModuleWithProviders} from '@angular/core';
22

33
import {
44
MdRippleModule,
5-
RtlModule,
5+
BidiModule,
66
ObserveContentModule,
77
PortalModule,
88
OverlayModule,
@@ -63,7 +63,7 @@ const MATERIAL_MODULES = [
6363
MdTooltipModule,
6464
OverlayModule,
6565
PortalModule,
66-
RtlModule,
66+
BidiModule,
6767
StyleModule,
6868
A11yModule,
6969
PlatformModule,
@@ -90,7 +90,7 @@ const MATERIAL_MODULES = [
9090
MdTabsModule.forRoot(),
9191
MdToolbarModule.forRoot(),
9292
PortalModule.forRoot(),
93-
RtlModule.forRoot(),
93+
BidiModule.forRoot(),
9494
ObserveContentModule.forRoot(),
9595

9696
// These modules include providers.

src/lib/select/select.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {OverlayContainer} from '../core/overlay/overlay-container';
1515
import {MdSelect, MdSelectFloatPlaceholderType} from './select';
1616
import {MdSelectDynamicMultipleError, MdSelectNonArrayValueError} from './select-errors';
1717
import {MdOption} from '../core/option/option';
18-
import {Dir} from '../core/rtl/dir';
18+
import {Directionality} from '../core/bidi/index';
1919
import {
2020
ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule
2121
} from '@angular/forms';
@@ -64,7 +64,7 @@ describe('MdSelect', () => {
6464

6565
return {getContainerElement: () => overlayContainerElement};
6666
}},
67-
{provide: Dir, useFactory: () => {
67+
{provide: Directionality, useFactory: () => {
6868
return dir = { value: 'ltr' };
6969
}},
7070
{provide: ViewportRuler, useClass: FakeViewportRuler}

src/lib/select/select.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
import {MdOption, MdOptionSelectionChange} from '../core/option/option';
2121
import {ENTER, SPACE} from '../core/keyboard/keycodes';
2222
import {FocusKeyManager} from '../core/a11y/focus-key-manager';
23-
import {Dir} from '../core/rtl/dir';
23+
import {Directionality} from '../core/bidi/index';
2424
import {Observable} from 'rxjs/Observable';
2525
import {Subscription} from 'rxjs/Subscription';
2626
import {transformPlaceholder, transformPanel, fadeInContent} from './select-animations';
@@ -303,7 +303,8 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
303303

304304
constructor(private _element: ElementRef, private _renderer: Renderer,
305305
private _viewportRuler: ViewportRuler, private _changeDetectorRef: ChangeDetectorRef,
306-
@Optional() private _dir: Dir, @Self() @Optional() public _control: NgControl,
306+
@Optional() private _dir: Directionality,
307+
@Self() @Optional() public _control: NgControl,
307308
@Attribute('tabindex') tabIndex: string) {
308309
if (this._control) {
309310
this._control.valueAccessor = this;

0 commit comments

Comments
 (0)