-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(directionality): a provider to get the overall directionality #4044
Conversation
src/lib/core/rtl/dir.ts
Outdated
@@ -8,36 +8,42 @@ import { | |||
EventEmitter | |||
} from '@angular/core'; | |||
|
|||
import {Directionality} from './directionality'; | |||
export {Directionality} from './directionality'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change the directory name from rtl
to bidi
and add an index.d.ts
that re-exports the public symbols?
We should also rename the NgModule to BidiModule
src/lib/core/rtl/dir.ts
Outdated
@@ -8,36 +8,42 @@ import { | |||
EventEmitter | |||
} from '@angular/core'; | |||
|
|||
import {Directionality} from './directionality'; | |||
export {Directionality} from './directionality'; | |||
|
|||
export type LayoutDirection = 'ltr' | 'rtl'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of renaming LayoutDirection
to just Direction
now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
src/lib/core/rtl/dir.ts
Outdated
}) | ||
export class RtlModule { | ||
/** @deprecated */ | ||
static forRoot(): ModuleWithProviders { | ||
return { | ||
ngModule: RtlModule, | ||
providers: [] | ||
providers: [Directionality] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make a provider for Directionality
similar to LiveAnnouncer
? Something like
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();
}
};
Has to use the function
syntax rather than () =>
due to an open bug in the metadata extractor
(should live in directionality.ts
)
src/lib/core/rtl/directionality.ts
Outdated
*/ | ||
@Injectable() | ||
export class Directionality { | ||
value: LayoutDirection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type def for LayoutDirection
should move to this file
src/lib/core/rtl/directionality.ts
Outdated
import {LayoutDirection} from './dir'; | ||
|
||
/** | ||
* A provider to get the direction outside of angular on the `html` or `body` elements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"A provider" isn't really accurate (it's just a class that's provided). It can just be something like
The directionality (LTR / RTL) context for the application (or a subtree of it).
Exposes the current direction and a stream of direction changes.
src/lib/core/rtl/directionality.ts
Outdated
|
||
constructor() { | ||
this.value = | ||
(document.body.getAttribute('dir') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"
. I'd like to avoid using getComputedStyle
here, though, since we're already calling it for the theming check.
Let's just add a TODO
to handle auto with this background info.
src/lib/core/rtl/directionality.ts
Outdated
|
||
constructor() { | ||
this.value = | ||
(document.body.getAttribute('dir') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also check for the existence of document
before dereferencing it (for platform-server)
1793720
to
5e6040d
Compare
cda2cc9
to
ba756f5
Compare
@EladBezalel ready for another pass? |
Yep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple last things to address
src/lib/core/bidi/directionality.ts
Outdated
public change = new EventEmitter<void>(); | ||
|
||
constructor() { | ||
if (document) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need typeof document
here in order to not error on Angular Universal. This will need to eventually be augmented with using universal's document service.
src/lib/core/bidi/directionality.ts
Outdated
// 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') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the dir
property instead of getAttribute
? I believe they should be equivalent (but would be shorter)
src/lib/core/bidi/directionality.ts
Outdated
@Injectable() | ||
export class Directionality { | ||
value: Direction = 'ltr'; | ||
public change = new EventEmitter<void>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need unit tests for the following (creating a new bidi.spec.ts
):
- Directionality reads
dir
from the html element if not specified on the body - Directionality reads
dir
from the body even it is also specified on the html element - Directionality defaults to
ltr
if nothing is specified on either body or the html element -
Dir
provides itself asDirectionality
-
Dir
emits a change event when the value changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How before the tests i can add the dir attribute to the html and the body elements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the top-level beforeEach
grab the current dir
on each and then in the top-level afterEach
restore it. Then you can just change it for individual blocks.
1b22426
to
d4f0d53
Compare
function initDir () { | ||
document.documentElement.dir = ''; | ||
document.body.dir = ''; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this something like clearDocumentDirAttributes
? Also move to the bottom of the file, after the tests but before the test components
|
||
TestBed.compileComponents(); | ||
|
||
initDir(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There needs to be an afterEach
that restores the dir
attributes to whatever they were before.
|
||
/** Test component without Dir. */ | ||
@Component({ | ||
selector: 'test-app-without-dir', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need a selector for components instantiated via TestBed
src/lib/core/bidi/directionality.ts
Outdated
public change = new EventEmitter<void>(); | ||
|
||
constructor() { | ||
if (typeof document) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typeof document === 'object' && !!document
.
We have an isBrowser
property on Platform
now for things like this, but we can adjust that later (since it involves bringing in PlatformModule
)
selector: 'dir-test', | ||
template: `<div></div>` | ||
}) | ||
class DirTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this InjectsDirectionality
with selector injects-directionality
. You can also completely replace TestAppWithoutDir
with this component.
</div> | ||
` | ||
}) | ||
class TestAppWithDir { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can just call this ElementWithDir
}); | ||
}); | ||
|
||
describe('Dir directive', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be one top-level describe
block that does configureTestingModule
, importing BidiModule
. You can then have two sub describe
blocks ("without dir directive", "with dir directive"). Then you can have a separate beforeEach
that does the createComponent
in each and the query for the directive you're looking for (to reduce repetition).
describe('Dir directive', () => { | ||
beforeEach(async(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [Dir, TestAppWithDir, DirTest] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI you shouldn't put directives you're testing directly into the declarations
of the testing module; better to import the NgModule
they live in for real (so BidiModule
here)
it('should provide itself as Directionality', () => { | ||
let fixture = TestBed.createComponent(TestAppWithDir); | ||
let testComponent = | ||
getDebugNode(fixture.nativeElement.querySelector('dir-test')).componentInstance; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use By.directive
instead:
const injectedDirectionality =
fixture.debugElement.query(By.directive(InjectsDirectionality)).dir;
(here and elsewhere)
@@ -65,7 +65,7 @@ describe('MdAutocomplete', () => { | |||
|
|||
return {getContainerElement: () => overlayContainerElement}; | |||
}}, | |||
{provide: Dir, useFactory: () => ({value: dir})}, | |||
{provide: Directionality, useFactory: () => ({value: dir})}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than changing all of these tests to add the Directionality
, we now have a MdCommonModule
that all of the components import. You can add BidiModule
to the imports of the common module.
742f79f
to
d712b9d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@EladBezalel just needs rebase |
ce40d79
to
ac874fe
Compare
I've rebased it |
Hmm, changing the actual |
- 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 angular#3600
Changed |
Caretaker note: some people were importing |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
html
andbody
elements fordir
attribute and sets the Directionality service value to itfixes #3600