diff --git a/demo/app/app-routing.module.ts b/demo/app/app-routing.module.ts index 30ad9df61..88575042e 100644 --- a/demo/app/app-routing.module.ts +++ b/demo/app/app-routing.module.ts @@ -1,10 +1,16 @@ import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { + ExtraOptions, + RouterModule, + Routes, +} from '@angular/router'; import { ComponentsComponent } from './components/components.component'; import { componentsList } from './components/components.constant'; +const routerOptions: ExtraOptions = {anchorScrolling: 'enabled'}; + const routes: Routes = [ { path: 'components', @@ -19,7 +25,7 @@ const routes: Routes = [ @NgModule({ - imports: [RouterModule.forRoot(routes)], + imports: [RouterModule.forRoot(routes, routerOptions)], exports: [RouterModule], }) export class AppRoutingModule { } diff --git a/demo/app/components/link/link.component.html b/demo/app/components/link/link.component.html index 649d719d3..7974980b4 100644 --- a/demo/app/components/link/link.component.html +++ b/demo/app/components/link/link.component.html @@ -1,4 +1,4 @@ - +
An external link using the 'warn' theme.
+ +
+ A local fragment link to go down +
+ + +
+ + + +
+ A local fragment link to go up +
+
+ + +
diff --git a/demo/app/components/link/link.component.ts b/demo/app/components/link/link.component.ts index c200f47fa..a12ee07ec 100644 --- a/demo/app/components/link/link.component.ts +++ b/demo/app/components/link/link.component.ts @@ -6,7 +6,7 @@ import { Component } from '@angular/core'; templateUrl: './link.component.html', }) export class LinkComponent { - localDestination: string[] = ['/components/copy']; - externalDestination: string = `http://google.com`; + localDestination = ['/components/copy']; + externalDestination = `http://google.com`; external = true; } diff --git a/terminus-ui/link/src/link.component.html b/terminus-ui/link/src/link.component.html index 3bafcbaf5..b69db614b 100644 --- a/terminus-ui/link/src/link.component.html +++ b/terminus-ui/link/src/link.component.html @@ -1,18 +1,20 @@ + diff --git a/terminus-ui/link/src/link.component.md b/terminus-ui/link/src/link.component.md index c4bbc86ed..e6974ca20 100644 --- a/terminus-ui/link/src/link.component.md +++ b/terminus-ui/link/src/link.component.md @@ -8,6 +8,8 @@ - [Basic usage](#basic-usage) - [External links](#external-links) - [Tab index](#tab-index) +- [Local URL fragments](#local-url-fragments) + - [Router changes to support local links](#router-changes-to-support-local-links) @@ -18,7 +20,7 @@ Wrap your link text and define a destination: ```html My link ``` @@ -47,3 +49,54 @@ A custom tabindex can also be set: [tabIndex]="2" >My link ``` + + +## Local URL fragments + +Local fragements are supported for deep linking within a page: + +```html +My link + +``` + +If no destination is defined, it will fallback to the local page: `['.']`: + +```html +My link + +``` + +### Router changes to support local links + +There are a couple needed Router configuration changes to support local links: + +```typescript +import { NgModule } from '@angular/core'; +import { + ExtraOptions, + RouterModule, + Routes, +} from '@angular/router'; + +const myRoutes: Routes = [...]; +const routerOptions: ExtraOptions = { + anchorScrolling: 'enabled', + scrollPositionRestoration: 'enabled', +}; + +@NgModule({ + ... + imports: [RouterModule.forRoot(myRoutes, routerOptions)], + ... +}) +``` + +> Learn more about Angular's `ExtraOptions` here: https://angular.io/api/router/ExtraOptions diff --git a/terminus-ui/link/src/link.component.spec.ts b/terminus-ui/link/src/link.component.spec.ts index 3a836b4ca..3a67eb1ac 100644 --- a/terminus-ui/link/src/link.component.spec.ts +++ b/terminus-ui/link/src/link.component.spec.ts @@ -1,14 +1,19 @@ import { APP_BASE_HREF } from '@angular/common'; import { Component, + Provider, + Type, ViewChild, } from '@angular/core'; import { + async, ComponentFixture, + TestBed, tick, } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { RouterModule } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { getDomAttribute } from '@terminus/ngx-tools'; import { createComponent } from '@terminus/ngx-tools/testing'; import { TsStyleThemeTypes } from '@terminus/ui/utilities'; @@ -18,18 +23,20 @@ import { TsLinkModule } from './link.module'; @Component({ template: ` - - My Link Text - + + My Link Text + `, }) class TestHostComponent { - public destination!: any; + public destination!: undefined | string | string[]; + public fragment!: undefined | string; public isExternal!: boolean; public tabIndex!: number | undefined; public theme: TsStyleThemeTypes = 'primary'; @@ -45,19 +52,12 @@ describe(`TsLinkComponent`, function() { let link: HTMLElement; let linkComponent: TsLinkComponent; - beforeEach(() => { - fixture = createComponent( - TestHostComponent, - [{ - provide: APP_BASE_HREF, - useValue: '/my/app', - }], - [TsLinkModule, RouterModule.forRoot([])], - ); + beforeEach(async(() => { + fixture = createComponent(TestHostComponent, [], [TsLinkModule, RouterTestingModule]); component = fixture.componentInstance; linkComponent = component.linkComponent; fixture.detectChanges(); - }); + })); test(`should exist`, () => { @@ -68,13 +68,38 @@ describe(`TsLinkComponent`, function() { describe(`isInternal`, () => { test(`should default and retrieve`, () => { - link = fixture.debugElement.query(By.css('.c-link')).nativeElement as HTMLElement; + link = fixture.debugElement.query(By.css('.c-link')).nativeElement; component.isExternal = false; component.destination = ['/#']; expect(link.classList).toContain('qa-link-internal'); }); + + describe(`fragment`, function() { + + test(`should correctly add the fragment`, function() { + fixture.componentInstance.destination = ['foo', 'bar']; + fixture.componentInstance.fragment = 'fooBar-bing'; + fixture.detectChanges(); + link = fixture.debugElement.query(By.css('.ts-link')).nativeElement; + + const href = fixture.debugElement.query(By.css('a')).nativeElement.getAttribute('href'); + expect(href).toEqual('/foo/bar#fooBar-bing'); + }); + + + test(`should use a route to the current page if none is passed in`, function() { + fixture.componentInstance.fragment = 'fooBar-bing'; + fixture.detectChanges(); + link = fixture.debugElement.query(By.css('.ts-link')).nativeElement; + + const href = fixture.debugElement.query(By.css('a')).nativeElement.getAttribute('href'); + expect(href).toEqual('/#fooBar-bing'); + }); + + }); + }); @@ -84,7 +109,7 @@ describe(`TsLinkComponent`, function() { component.destination = 'www.google.com'; component.isExternal = true; fixture.detectChanges(); - link = fixture.debugElement.query(By.css('.c-link')).nativeElement as HTMLElement; + link = fixture.debugElement.query(By.css('.c-link')).nativeElement; expect(link.classList).toContain('qa-link-external'); expect(link.children[0].textContent).toContain('open_in_new'); @@ -100,7 +125,7 @@ describe(`TsLinkComponent`, function() { component.tabIndex = 9; fixture.detectChanges(); - link = fixture.debugElement.query(By.css('.c-link')).nativeElement as HTMLElement; + link = fixture.debugElement.query(By.css('.c-link')).nativeElement; expect(link.tabIndex).toEqual(9); }); @@ -111,13 +136,13 @@ describe(`TsLinkComponent`, function() { describe(`theme`, function() { test(`should set the appropriate class`, function() { - link = fixture.debugElement.query(By.css('.ts-link')).nativeElement as HTMLElement; + link = fixture.debugElement.query(By.css('.ts-link')).nativeElement; expect(link.classList).toContain('ts-link--primary'); component.theme = 'accent'; fixture.detectChanges(); - link = fixture.debugElement.query(By.css('.ts-link')).nativeElement as HTMLElement; + link = fixture.debugElement.query(By.css('.ts-link')).nativeElement; expect(link.classList).not.toContain('ts-link--primary'); expect(link.classList).toContain('ts-link--accent'); diff --git a/terminus-ui/link/src/link.component.ts b/terminus-ui/link/src/link.component.ts index 861582d30..fd4472dff 100644 --- a/terminus-ui/link/src/link.component.ts +++ b/terminus-ui/link/src/link.component.ts @@ -23,6 +23,7 @@ import { TsStyleThemeTypes } from '@terminus/ui/utilities'; * *