Skip to content
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

enabled arrow icons to jump to previous and next lessons #1041

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6b8794c
enabled arrow icons to jump to previous and next lessons
sunilj74 Sep 13, 2019
7798eb3
Merge branch 'master' into lesson_1024
sunilj74 Sep 13, 2019
d3758f2
Enabled next and previous buttons to navigate to different lessons on…
sunilj74 Sep 25, 2019
0667163
Merge branch 'lesson_1024' of https://github.com/codelab-fun/codelab …
sunilj74 Sep 25, 2019
e3be024
made presentation slide optional in constructor in title and closing …
sunilj74 Sep 27, 2019
bfc44b7
added tests to title and closing slides
sunilj74 Oct 3, 2019
89831ea
dropped calls to setPrevious from closing slide and calls to setNext …
sunilj74 Oct 3, 2019
e84f72b
merged with master
sunilj74 Oct 3, 2019
caeb0bc
fixed linting errors
sunilj74 Oct 3, 2019
60f6141
Changed to createSpy in tests. Also changed some method names to more…
sunilj74 Oct 11, 2019
5fe9484
Merge branch 'master' into lesson_1024
sunilj74 Oct 11, 2019
52958ef
removed complicated code from title and closing slides
sunilj74 Oct 24, 2019
feb7744
moved previous and next link features to a service
sunilj74 Nov 11, 2019
ef0f7d5
added commit logs
sunilj74 Nov 12, 2019
e91ae03
Merge branch 'master' into lesson_1024
sunilj74 Nov 12, 2019
d9ad958
Merge branch 'master' into lesson_1024
NothingEverHappens Nov 14, 2019
f524ec9
changed menu-route service to receive ActivatedRoute while getting ne…
sunilj74 Nov 25, 2019
28ddb49
Merge branch 'master' into lesson_1024
sunilj74 Nov 25, 2019
4126829
Merge branch 'lesson_1024' of https://github.com/codelab-fun/codelab …
sunilj74 Nov 25, 2019
65c6403
fixed tests for menu-route.service.ts
sunilj74 Nov 25, 2019
f5acd63
added more details to TODO action. moved redundant code into functions
sunilj74 Dec 15, 2019
c9c3956
Merge branch 'master' into lesson_1024
sunilj74 Dec 15, 2019
5bde57b
switched variables to direct returns. also removed an unecessary if c…
sunilj74 Dec 16, 2019
154b746
removed a wrong TODO
sunilj74 Dec 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions apps/codelab/src/app/codelabs/angular/menu-route.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { TestBed } from '@angular/core/testing';

import { MenuRouteService } from './menu-route.service';
import { ActivatedRoute } from '@angular/router';
import { MENU_ROUTES, MenuRoutes } from '../../common';

describe('MenuRouteService', () => {
const menuRoutes: MenuRoutes = [
{
path: 'previouslesson',
prod: true
},
{
path: 'currentlesson',
prod: true
},
{
path: 'nextlesson',
prod: true
}
];

const activatedRouteStub = {
snapshot: {
pathFromRoot: [
{
routeConfig: menuRoutes[1]
}
]
}
} as ActivatedRoute;

beforeEach(() =>
TestBed.configureTestingModule({
providers: [{ provide: MENU_ROUTES, useValue: menuRoutes }]
})
);

it('should be created', () => {
const service: MenuRouteService = TestBed.inject(MenuRouteService);
expect(service).toBeTruthy();
});

it('getPreviousLink should return previouslesson', () => {
const service: MenuRouteService = TestBed.inject(MenuRouteService);
const previousLink = service.getPreviousLink(activatedRouteStub);
expect(previousLink).toEqual('../../' + menuRoutes[0].path);
});

it('getNextLink should return nextlesson', () => {
const service: MenuRouteService = TestBed.inject(MenuRouteService);
const nextLink = service.getNextLink(activatedRouteStub);
expect(nextLink).toEqual('../../' + menuRoutes[2].path);
});
});
59 changes: 59 additions & 0 deletions apps/codelab/src/app/codelabs/angular/menu-route.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Injectable, Inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MENU_ROUTES, MenuRoute } from '../../common';

@Injectable({
providedIn: 'root'
})
export class MenuRouteService {
constructor(@Inject(MENU_ROUTES) private readonly menuRoutes) {}

getPreviousLink(activeRoute: ActivatedRoute): string {
const index = this.getCurrentIndex(activeRoute);
if (index > 0) {
return this.getMenuRoutePathByIndex(index - 1);
}
return '';
}

getNextLink(activeRoute: ActivatedRoute): string {
const index = this.getCurrentIndex(activeRoute);
if (index < this.menuRoutes.length - 1) {
return this.getMenuRoutePathByIndex(index + 1);
}
return '';
}

private getCurrentIndex(activeRoute: ActivatedRoute): number {
// TODO: figure out a way to inject the ActivatedRoute instead of parameter
// This method gets the index of the current menuRoute. Ideally we should be able
// to inject in the ActivatedRoute in the constructor. However we noticed that
// probably because this is a service, activatedRoute has the value when the
// service is constructed and not the current activated route. We are using a
// workaround now which expects the calling method to pass the current activated
// route. Fix this to use DI.
const config = activeRoute.snapshot.pathFromRoot
.map(a => a.routeConfig)
.find(r => r && (r as MenuRoute).prod);
if (config == null) {
return -1;
}
return this.menuRoutes.findIndex(c => c.path === config.path);
}

private getMenuRouteByIndex(index: number) {
return this.menuRoutes[index];
}

private getMenuRoutePathByIndex(index: number): string {
const indexRoute = this.getMenuRouteByIndex(index);
if (indexRoute != null) {
let path = indexRoute.path;
if (path) {
path = '../../' + path;
}
return path;
}
return '';
}
}
2 changes: 1 addition & 1 deletion apps/codelab/src/app/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Route } from '@angular/router';

export type MenuRoutes = MenuRoute[];

interface MenuRoute extends Route {
export interface MenuRoute extends Route {
name?: string;
description?: string;
page?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CodelabClosingSlideComponent } from './codelab-closing-slide.component';
import { ActivatedRoute } from '@angular/router';
import { SlidesDeckComponent } from '@codelab/slides/src/lib/deck/deck.component';
import { MenuRoutes } from '../../../common';
import { MenuRouteService } from '../../../codelabs/angular/menu-route.service';

describe('CodelabClosingSlideComponent', () => {
let component: CodelabClosingSlideComponent;
let fixture: ComponentFixture<CodelabClosingSlideComponent>;

const menuRouteService = {
getNextLink: function() {
return 'nextlesson';
}
};

const slidesDeckComponentStub = {
setNext: jasmine.createSpy('setNext')
};

const menuRoutes: MenuRoutes = [
{
path: 'previouslesson',
prod: true
},
{
path: 'currentlesson',
prod: true
},
{
path: 'nextlesson',
prod: true
}
];

const activatedRouteStub = {
snapshot: { pathFromRoot: [{ routeConfig: menuRoutes[1] }] }
};

beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: MenuRouteService, useValue: menuRouteService },
{ provide: SlidesDeckComponent, useValue: slidesDeckComponentStub }
],
declarations: [CodelabClosingSlideComponent]
}).compileComponents();
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { Component, Input, OnInit } from '@angular/core';
import { SlidesDeckComponent } from '@codelab/slides/src/lib/deck/deck.component';
import { MenuRouteService } from '../../../codelabs/angular/menu-route.service';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'codelab-closing-slide',
templateUrl: './codelab-closing-slide.component.html',
styleUrls: ['./codelab-closing-slide.component.css']
})
export class CodelabClosingSlideComponent implements OnInit {
export class CodelabClosingSlideComponent {
@Input() header: String;
@Input() body: String;
@Input() footer: String;

constructor() {}

ngOnInit() {}
constructor(
private readonly activeRoute: ActivatedRoute,
private readonly menuRouteService: MenuRouteService,
private readonly presentation: SlidesDeckComponent
) {
if (this.presentation != null) {
const nextLink = this.menuRouteService.getNextLink(this.activeRoute);
this.presentation.setNext(nextLink);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop empty ngOnInit while you're here?

}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,66 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { By } from '@angular/platform-browser';

import { TitleSlideComponent } from './title-slide.component';
import { CodelabRippleAnimationComponent } from './ripple-animation/codelab-ripple-animation.component';
import { SlidesDeckComponent } from '@codelab/slides/src/lib/deck/deck.component';
import { MenuRouteService } from '../../../codelabs/angular/menu-route.service';
import { MenuRoutes } from '../../../common';
import { ActivatedRoute } from '@angular/router';

describe('TitleSlideComponent', () => {
let component: TitleSlideComponent;
let fixture: ComponentFixture<TitleSlideComponent>;

const menuRouteService = {
getPreviousLink: function() {
return 'previouslesson';
}
};

const slidesDeckComponentStub = {
previousLink: '',
nextLink: '',
setPrevious: jasmine.createSpy('setPrevious')
};

const menuRoutes: MenuRoutes = [
{
path: 'previouslesson',
prod: true
},
{
path: 'currentlesson',
prod: true
},
{
path: 'nextlesson',
prod: true
}
];

const activatedRouteStub = {
snapshot: {
pathFromRoot: [
{
routeConfig: menuRoutes[1]
}
]
}
};

beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: MenuRouteService, useValue: menuRouteService },
{
provide: SlidesDeckComponent,
useFactory: () => slidesDeckComponentStub
}
],
imports: [RouterTestingModule],
declarations: [CodelabRippleAnimationComponent, TitleSlideComponent]
}).compileComponents();
}));
Expand All @@ -24,6 +75,10 @@ describe('TitleSlideComponent', () => {
expect(component).toBeTruthy();
});

it('should call setPrevious', () => {
expect(slidesDeckComponentStub.setPrevious).toHaveBeenCalled();
});

it('should render a title', () => {
component.title = 'awesome title';
fixture.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Component, Input } from '@angular/core';
import { SlidesDeckComponent } from '@codelab/slides/src/lib/deck/deck.component';
import { MenuRouteService } from '../../../codelabs/angular/menu-route.service';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'codelab-title-slide',
Expand All @@ -9,4 +12,17 @@ export class TitleSlideComponent {
@Input() title: string;
@Input() description: string;
@Input() prereqs: string;

constructor(
private readonly activeRoute: ActivatedRoute,
private readonly menuRouteService: MenuRouteService,
private readonly presentation: SlidesDeckComponent
) {
if (this.presentation != null) {
const previousLink = this.menuRouteService.getPreviousLink(
this.activeRoute
);
this.presentation.setPrevious(previousLink);
}
}
}
2 changes: 1 addition & 1 deletion libs/slides/src/lib/arrows/slides-arrows.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, HostBinding } from '@angular/core';
import { Component, HostBinding, Input } from '@angular/core';
import { SlidesDeckComponent } from '../deck/deck.component';

/**
Expand Down
37 changes: 29 additions & 8 deletions libs/slides/src/lib/deck/deck.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
TemplateRef
} from '@angular/core';

import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
selector: 'slide-deck',
Expand All @@ -27,13 +27,16 @@ export class SlidesDeckComponent {
@Output() slideAdded = new EventEmitter<{ index: number; id: string }>();
@HostBinding('class.has-milestone') hasMilestone = false;
private milestone = '';
private previousLink: string;
private nextLink: string;

constructor(
private readonly cdr: ChangeDetectorRef,
@Optional() private readonly route: ActivatedRoute
private readonly router: Router,
@Optional() private readonly activeRoute: ActivatedRoute
) {
if (route) {
this.milestone = route.snapshot.queryParams.milestone;
if (activeRoute) {
this.milestone = activeRoute.snapshot.queryParams.milestone;
this.hasMilestone = !!this.milestone;
}
}
Expand All @@ -51,18 +54,36 @@ export class SlidesDeckComponent {
}

nextSlide() {
this.goToSlide(this.activeSlideIndex + 1);
if (this.activeSlideIndex + 1 < this.slides.length) {
this.goToSlide(this.activeSlideIndex + 1);
} else if (this.nextLink) {
this.router.navigate([this.nextLink], { relativeTo: this.activeRoute });
}
}

previousSlide() {
this.goToSlide(this.activeSlideIndex - 1);
if (this.activeSlideIndex > 0) {
this.goToSlide(this.activeSlideIndex - 1);
} else if (this.previousLink) {
this.router.navigate([this.previousLink], {
relativeTo: this.activeRoute
});
}
}

canGoNext(): boolean {
return this.activeSlideIndex + 1 < this.slides.length;
return this.activeSlideIndex + 1 < this.slides.length || !!this.nextLink;
}

canGoPrevious(): boolean {
return this.activeSlideIndex > 0;
return this.activeSlideIndex > 0 || !!this.previousLink;
}

public setPrevious(previousLink) {
this.previousLink = previousLink;
}

public setNext(nextLink) {
this.nextLink = nextLink;
}
}