ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
899 lines (871 loc) • 29.7 kB
text/typescript
import { Component, DebugElement, Injectable, ViewChild } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ExtraOptions, Router, RouteReuseStrategy, ROUTER_CONFIGURATION } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { OHAYO_I18N_TOKEN, OhayoLocaleModule, OhayoLocaleService, en_US, MenuService, ScrollService, WINDOW, zh_CN } from '@ohayo/theme';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { Observable } from 'rxjs';
import { OhayoI18NServiceFake } from '../../theme/src/services/i18n/i18n';
import { ReuseTcomponentsomponent } from './reuse-tab.component';
import { ReuseCustomContextMenu, ReuseItem, ReuseTabMatchMode, ReuseTabRouteParamMatchMode } from './reuse-tab.interfaces';
import { ReuseTabModule } from './reuse-tab.module';
import { ReuseTabService } from './reuse-tab.service';
import { ReuseTabStrategy } from './reuse-tab.strategy';
let i18nResult = 'zh';
()
class MockI18NServiceFake extends OhayoI18NServiceFake {
fanyi(_key: string): string {
return i18nResult;
}
}
describe('components: reuse-tab', () => {
let fixture: ComponentFixture<AppComponent>;
let dl: DebugElement;
let layoutComp: LayoutComponent;
let rtComp: ReuseTcomponentsomponent;
let srv: ReuseTabService;
let page: PageObject;
function genModule(needI18n: boolean = false): void {
TestBed.configureTestingModule({
declarations: [AppComponent, LayoutComponent, AComponent, BComponent, CComponent, DComponent, EComponent],
imports: [
OhayoLocaleModule,
ReuseTabModule,
RouterTestingModule.withRoutes(
[
{
path: '',
component: LayoutComponent,
children: [
{ path: 'a', component: AComponent },
{ path: 'b/:id', component: BComponent },
{ path: 'c', component: CComponent },
{ path: 'd', component: DComponent },
{ path: 'e', component: EComponent, data: { titleI18n: 'i18n' } },
{ path: 'lazy', loadChildren: 'lazy' },
{
path: 'leave',
component: DComponent,
canDeactivate: ['CanDeactivate'],
},
],
},
],
{ scrollPositionRestoration: 'disabled' },
),
],
providers: [
MenuService,
{ provide: WINDOW, useValue: window },
{
provide: RouteReuseStrategy,
useClass: ReuseTabStrategy,
deps: [ReuseTabService],
},
{
provide: 'CanDeactivate',
useValue: () => {
return new Observable((observer: any) => observer.next(false));
},
},
].concat(
!needI18n
? []
: [
{
provide: OHAYO_I18N_TOKEN,
useClass: MockI18NServiceFake,
} as any,
],
),
});
}
function createComp(layoutTemplate?: string): void {
if (layoutTemplate) TestBed.overrideTemplate(LayoutComponent, layoutTemplate);
fixture = TestBed.createComponent(AppComponent);
dl = fixture.debugElement;
fixture.detectChanges();
tick(101);
fixture.detectChanges();
srv = TestBed.inject<ReuseTabService>(ReuseTabService);
const router = TestBed.inject<Router>(Router) as Router;
router.routeReuseStrategy = new ReuseTabStrategy(srv);
page = new PageObject();
layoutComp = dl.query(By.directive(LayoutComponent)).injector.get<LayoutComponent>(LayoutComponent);
rtComp = dl.query(By.directive(ReuseTcomponentsomponent)).injector.get<ReuseTcomponentsomponent>(ReuseTcomponentsomponent);
spyOn(layoutComp, 'change');
spyOn(layoutComp, 'close');
flush();
discardPeriodicTasks();
}
afterEach(() => rtComp.ngOnDestroy());
describe('', () => {
beforeEach(fakeAsync(() => {
genModule();
createComp();
}));
describe('[default]', () => {
it('should be create an instance', () => {
page.expectCount(1);
});
it('should be add a tab when route changed', fakeAsync(() => {
page.to('#b').expectCount(2).end();
}));
it('should be change tab via click', fakeAsync(() => {
expect(layoutComp.change).not.toHaveBeenCalled();
page.to('#b').go(0);
expect(layoutComp.change).toHaveBeenCalled();
page.end();
}));
it('should be two tab in routing parameters', fakeAsync(() => {
page
.to('#b')
.tap(() => {
page.getEl('#b2').click();
page.cd();
})
.expectCount(3)
.end();
}));
});
describe('#close', () => {
it('should be close a tab', fakeAsync(() => {
page.to('#b').expectUrl(0, '/a').expectUrl(1, '/b/1').close(0).expectUrl(0, '/b/1');
expect(layoutComp.close).toHaveBeenCalled();
page.end();
}));
it('should show next tab when closed a has next tab', fakeAsync(() => {
srv.max = 10;
page
.to('#b')
.to('#c')
.go(1)
// a, b/1, c
.expectUrl(1, '/b/1')
.close(1)
.expectUrl(1, '/c')
.end();
}));
it('issues-363', fakeAsync(() => {
page.to('#b').expectCount(2).close(1).expectCount(1).expectAttr(0, 'closable', false).end();
}));
});
describe('#title', () => {
it(`should reset title via component`, fakeAsync(() => {
page.to('#c');
expect(page.list[page.count - 1].title).toBe(`new c title`);
page.end();
}));
it(`should reset title via service`, fakeAsync(() => {
page.to('#c');
srv.title = 'NEW TITLE';
expect(page.list[page.count - 1].title).toBe(`NEW TITLE`);
page.end();
}));
});
describe('[property]', () => {
describe('#mode', () => {
[ReuseTabMatchMode.Menu, ReuseTabMatchMode.MenuForce, ReuseTabMatchMode.URL].forEach(type => {
it(`with ${type}`, () => {
layoutComp.mode = type;
fixture.detectChanges();
expect(srv.mode).toBe(type);
});
});
});
describe('#debug', () => {
[true, false].forEach(type => {
it(`with ${type}`, () => {
layoutComp.debug = type;
fixture.detectChanges();
expect(srv.debug).toBe(type);
});
});
});
describe('#max', () => {
const MAX = 2;
beforeEach(() => {
layoutComp.max = MAX;
fixture.detectChanges();
});
it('should working', fakeAsync(() => {
page
.to('#b')
.expectCount(MAX)
.to('#c')
.expectCount(MAX + 1) // +1 => current page
.to('#d')
.expectCount(MAX + 1)
.end();
}));
});
describe('#allowClose', () => {
it('with true', fakeAsync(() => {
layoutComp.allowClose = true;
fixture.detectChanges();
page.to('#b');
expect(dl.queryAll(By.css('.reuse-tab__op')).length).toBe(2);
page.to('#c');
expect(dl.queryAll(By.css('.reuse-tab__op')).length).toBe(3);
page.end();
}));
it('with false', fakeAsync(() => {
layoutComp.allowClose = false;
fixture.detectChanges();
page.to('#b');
expect(dl.queryAll(By.css('.reuse-tab__op')).length).toBe(0);
page.to('#c');
expect(dl.queryAll(By.css('.reuse-tab__op')).length).toBe(0);
page.end();
}));
});
describe('#tabMaxWidth', () => {
it('with 100', () => {
layoutComp.tabMaxWidth = 100;
fixture.detectChanges();
const el = page.getEl('.reuse-tab__name-width');
expect(el != null).toBe(true);
expect(el.style.maxWidth).toBe(`100px`);
});
});
describe('#routeParamMatchMode', () => {
describe('with loos', () => {
it('should be only one tab', fakeAsync(() => {
layoutComp.routeParamMatchMode = 'loose';
fixture.detectChanges();
page.to('#b').to('#b2').to('#b3').expectCount(2);
}));
});
});
});
describe('[context-menu]', () => {
beforeEach(() => (srv.max = 10));
it('should closed current tab', fakeAsync(() => {
expect(layoutComp.close).not.toHaveBeenCalled();
page.to('#b').expectCount(2).openContextMenu(1).clickContentMenu('close').expectCount(1);
expect(layoutComp.close).toHaveBeenCalled();
page.end();
}));
it('should keeping tab if closed include multi prev tab', fakeAsync(() => {
let cTime = '';
page
.to('#b') // 1
.to('#c') // 2
.tap(() => (cTime = page.time))
.to('#d') // 3
.go(2)
.expectCount(4)
.openContextMenu(1)
.clickContentMenu('close')
.expectCount(3)
.expectActive(1, true)
.expectUrl(1, '/c')
.expectTime(cTime)
.end();
}));
it('should show the previous tab if the right not tab', fakeAsync(() => {
let aTime = '';
page
.tap(() => (aTime = page.time))
.to('#b') // 1
.expectCount(2)
.openContextMenu(1)
.clickContentMenu('close')
.expectCount(1)
.expectActive(0, true)
.expectUrl(0, '/a')
.expectTime(aTime)
.end();
}));
it('should show next tab if closed include multi right tab', fakeAsync(() => {
page
.to('#b') // 1
.to('#c') // 2
.to('#d') // 3
.go(1)
.expectCount(4)
.openContextMenu(1)
.clickContentMenu('close')
.expectCount(3)
.expectActive(1, true)
.expectUrl(1, '/c')
.end();
}));
it('should keeping tab when closed prev tab', fakeAsync(() => {
page.to('#b').expectCount(2).openContextMenu(0).clickContentMenu('close').expectCount(1).expectActive(0, true).end();
}));
it('should keeping tab when closed next tab', fakeAsync(() => {
page.to('#b').go(0).expectCount(2).openContextMenu(1).clickContentMenu('close').expectCount(1).expectActive(0, true).end();
}));
it('should keeping tab of closed right tab', fakeAsync(() => {
let bTime = '';
page
.to('#b') // 1
.tap(() => (bTime = page.time))
.to('#c') // 2
.to('#d') // 3
.go(1)
.expectCount(4)
.openContextMenu(1)
.clickContentMenu('closeRight')
.expectCount(2)
.expectActive(1, true)
.expectUrl(1, '/b/1')
.expectTime(bTime)
.end();
}));
it('should acitved select tab of closed right tab', fakeAsync(() => {
let bTime = '';
page
.to('#b') // 1
.tap(() => (bTime = page.time))
.to('#c') // 2
.to('#d') // 3
.openContextMenu(1)
.clickContentMenu('closeRight')
.expectCount(2)
.expectActive(1, true)
.expectUrl(1, '/b/1')
.expectTime(bTime)
.end();
}));
it('should keeping tab of close other tab', fakeAsync(() => {
let bTime = '';
page
.to('#b') // 1
.tap(() => (bTime = page.time))
.to('#c') // 2
.to('#d') // 3
.go(1)
.expectCount(4)
.openContextMenu(1)
.clickContentMenu('closeOther')
.expectCount(1)
.expectActive(0, true)
.expectUrl(0, '/b/1')
.expectTime(bTime)
.end();
}));
it('should trigger off close when closable: false', fakeAsync(() => {
page
.to('#b')
.tap(() => (srv.closable = false))
.cd()
.openContextMenu(1)
.expectCount(2)
.clickContentMenu('close')
.expectCount(2)
.end();
}));
it('should trigger off closeRight when is last', fakeAsync(() => {
page.to('#b').openContextMenu(1).expectCount(2).clickContentMenu('closeRight').expectCount(2).end();
}));
it('should hide context menu via click', fakeAsync(() => {
page.to('#b').openContextMenu(1).expectCount(2);
expect(document.querySelectorAll('.reuse-tab__cm').length).toBe(1);
document.dispatchEvent(new Event('click'));
page.cd();
expect(document.querySelectorAll('.reuse-tab__cm').length).toBe(0);
page.end();
}));
it('should be allow multi context menu', fakeAsync(() => {
page.to('#b').openContextMenu(1).expectCount(2);
expect(document.querySelectorAll('.reuse-tab__cm').length).toBe(1);
document.dispatchEvent(new MouseEvent('click', { button: 2 }));
page.cd();
expect(document.querySelectorAll('.reuse-tab__cm').length).toBe(1);
page.end();
}));
it('should be include non-closeable when push ctrl key', fakeAsync(() => {
page
.to('#e')
.openContextMenu(1)
.tap(() => expect(document.querySelector(`.reuse-tab__cm li[data-type="close"]`)!.classList).toContain('ant-menu-item-disabled'))
.openContextMenu(1, { ctrlKey: true })
.tap(() =>
expect(document.querySelector(`.reuse-tab__cm li[data-type="close"]`)!.classList).not.toContain('ant-menu-item-disabled'),
)
.expectCount(2)
.end();
}));
describe('custom menu', () => {
beforeEach(() => {
layoutComp.customContextMenu = [
{
id: 'custom1',
title: '自定义1',
fn: jasmine.createSpy('custom.menu.1'),
},
{
id: 'custom2',
title: '自定义2',
disabled: () => true,
fn: jasmine.createSpy('custom.menu.2'),
},
];
fixture.detectChanges();
});
it('should working', fakeAsync(() => {
expect(layoutComp.customContextMenu[0].fn).not.toHaveBeenCalled();
page.to('#b').openContextMenu(1).clickContentMenu('custom1');
expect(layoutComp.customContextMenu[0].fn).toHaveBeenCalled();
}));
it('should be disabled', fakeAsync(() => {
expect(layoutComp.customContextMenu[1].fn).not.toHaveBeenCalled();
page.to('#b').openContextMenu(1).clickContentMenu('custom2');
expect(layoutComp.customContextMenu[1].fn).not.toHaveBeenCalled();
}));
});
describe('#tabType', () => {
it('with line', () => {
layoutComp.tabType = 'line';
fixture.detectChanges();
expect(dl.queryAll(By.css('.reuse-tab__line')).length).toBe(1);
});
it('with card', () => {
layoutComp.tabType = 'card';
fixture.detectChanges();
expect(dl.queryAll(By.css('.reuse-tab__card')).length).toBe(1);
});
});
});
describe('[replace]', () => {
it('shoulde be working', fakeAsync(() => {
page.to('#a').to('#d').expectCount(2).expectUrl(0, '/a').expectUrl(1, '/d').cd();
srv.replace('/c');
page.cd(1).expectCount(2).expectUrl(0, '/a').expectUrl(1, '/c').end();
}));
});
describe('[routing]', () => {
it('[ohayojp #326] should be restricted by canDeactivate when changing tab', fakeAsync(() => {
let lTime = '';
page
.to('#leave')
.tap(() => (lTime = page.time))
.expectCount(2)
.expectActive(0, false)
.expectActive(1, true)
.go(0)
.expectActive(0, false)
.expectActive(1, true)
.expectTime(lTime);
}));
});
describe('#keepingScroll', () => {
const KSTIME = 2;
let ss: ScrollService;
let getScrollPositionSpy: jasmine.Spy;
beforeEach(() => {
ss = TestBed.inject(ScrollService) as ScrollService;
getScrollPositionSpy = spyOn(ss, 'getScrollPosition').and.returnValue([0, 666]);
spyOn(ss, 'scrollToPosition');
});
it('with true', fakeAsync(() => {
srv.keepingScroll = true;
page
.to('#a') // default page, not trigger store
.to('#b')
.cd(KSTIME)
.tap(() => {
expect(srv.items[0].position != null).toBe(true);
expect(srv.items[0].position![1]).toBe(666);
expect(ss.scrollToPosition).not.toHaveBeenCalled();
})
.to('#a')
.cd(KSTIME)
.tap(() => {
expect(srv.items[1].position != null).toBe(true);
expect(srv.items[1].position![1]).toBe(666);
expect(ss.scrollToPosition).toHaveBeenCalled();
})
.end();
}));
it('with false', fakeAsync(() => {
srv.keepingScroll = false;
page
.to('#a') // default page, not trigger store
.to('#b')
.cd(KSTIME)
.tap(() => {
expect(ss.getScrollPosition).not.toHaveBeenCalled();
})
.to('#a')
.cd(KSTIME)
.tap(() => {
expect(ss.getScrollPosition).not.toHaveBeenCalled();
})
.end();
}));
describe('should be delay trigger when has setting scrollPositionRestoration', () => {
it('with disabled (not delay)', fakeAsync(() => {
const cog = TestBed.inject(ROUTER_CONFIGURATION) as ExtraOptions;
cog.scrollPositionRestoration = 'disabled';
srv.keepingScroll = true;
page
.to('#a') // default page, not trigger store
.to('#b')
.to('#a')
.tap(() => {
expect(ss.scrollToPosition).toHaveBeenCalled();
})
.end();
}));
it('with enabled (must delay)', fakeAsync(() => {
const cog = TestBed.inject(ROUTER_CONFIGURATION) as ExtraOptions;
cog.scrollPositionRestoration = 'enabled';
srv.keepingScroll = true;
page
.to('#a') // default page, not trigger store
.to('#b')
.to('#a')
.cd(KSTIME)
.tap(() => {
expect(ss.scrollToPosition).toHaveBeenCalled();
})
.end();
}));
it('with top (must delay)', fakeAsync(() => {
const cog = TestBed.inject(ROUTER_CONFIGURATION) as ExtraOptions;
cog.scrollPositionRestoration = 'top';
srv.keepingScroll = true;
page
.to('#a') // default page, not trigger store
.to('#b')
.to('#a')
.cd(KSTIME)
.tap(() => {
expect(ss.scrollToPosition).toHaveBeenCalled();
})
.end();
}));
});
describe('#keepingScrollContainer', () => {
beforeEach(() => {
const cog = TestBed.inject(ROUTER_CONFIGURATION) as ExtraOptions;
cog.scrollPositionRestoration = 'disabled';
layoutComp.keepingScroll = true;
});
it('with window', fakeAsync(() => {
layoutComp.keepingScrollContainer = window;
fixture.detectChanges();
page
.to('#a') // default page, not trigger store
.to('#b')
.cd(KSTIME)
.tap(() => {
expect(srv.items[0].position != null).toBe(true);
expect(srv.items[0].position![1]).toBe(666);
expect(getScrollPositionSpy.calls.mostRecent().args[0]).toBe(window);
})
.end();
}));
it('with Element', fakeAsync(() => {
const el = document.querySelector('#children');
layoutComp.keepingScrollContainer = el;
fixture.detectChanges();
page
.to('#a') // default page, not trigger store
.to('#b')
.cd(KSTIME)
.tap(() => {
expect(srv.items[0].position != null).toBe(true);
expect(srv.items[0].position![1]).toBe(666);
expect(getScrollPositionSpy.calls.mostRecent().args[0]).toBe(el);
})
.end();
}));
it('with String', fakeAsync(() => {
layoutComp.keepingScrollContainer = '#children';
fixture.detectChanges();
page
.to('#a') // default page, not trigger store
.to('#b')
.cd(KSTIME)
.tap(() => {
expect(srv.items[0].position != null).toBe(true);
expect(srv.items[0].position![1]).toBe(666);
expect(getScrollPositionSpy.calls.mostRecent().args[0]).toBe(document.querySelector('#children'));
})
.end();
}));
});
});
});
describe('[refresh]', () => {
beforeEach(() => genModule(false));
it('should be can not call _onReuseInit when router-outlet not define (activate) event in refresh active tab', fakeAsync(() => {
createComp(`<reuse-tab #comp [mode]="mode"></reuse-tab><router-outlet></router-outlet>`);
let time = 0;
page
.to('#a')
.tap(() => (time = +page.time))
.openContextMenu(0)
.clickContentMenu('refresh');
expect(time).toBe(+page.time);
}));
it('should be call _onReuseInit when refresh active tab', fakeAsync(() => {
createComp(`<reuse-tab #comp [mode]="mode"></reuse-tab><router-outlet (activate)="comp.activate($event)"></router-outlet>`);
page.to('#a').openContextMenu(0);
spyOn(srv.componentRef.instance, '_onReuseInit');
page.clickContentMenu('refresh');
expect(srv.componentRef.instance._onReuseInit).toHaveBeenCalled();
}));
it('should be call _onReuseInit when refresh non-active tab', fakeAsync(() => {
createComp(`<reuse-tab #comp [mode]="mode"></reuse-tab><router-outlet (activate)="comp.activate($event)"></router-outlet>`);
page.to('#a').to('#b').openContextMenu(0);
spyOn(srv.items[0]._handle.componentRef.instance, '_onReuseInit');
page.clickContentMenu('refresh');
expect(srv.items[0]._handle.componentRef.instance._onReuseInit).toHaveBeenCalled();
}));
it('should be call _onReuseInit when refresh non-active tab and not define (activate) event', fakeAsync(() => {
createComp(`<reuse-tab #comp [mode]="mode"></reuse-tab><router-outlet></router-outlet>`);
page.to('#a').to('#b').openContextMenu(0);
spyOn(srv.items[0]._handle.componentRef.instance, '_onReuseInit');
page.clickContentMenu('refresh');
expect(srv.items[0]._handle.componentRef.instance._onReuseInit).toHaveBeenCalled();
}));
});
describe('[i18n]', () => {
it('should be rendered', fakeAsync(() => {
genModule(true);
createComp();
page.to('#e').expectAttr(1, 'title', 'zh');
i18nResult = 'en';
TestBed.inject(OHAYO_I18N_TOKEN).use('en');
page.cd().expectAttr(1, 'title', 'en').end();
}));
it('#context-menu-text', fakeAsync(() => {
genModule();
createComp();
page.to('#b').openContextMenu(1);
expect(document.querySelector('[data-type="close"]')!.textContent).toBe(zh_CN.reuseTab.close);
TestBed.inject<OhayoLocaleService>(OhayoLocaleService).setLocale(en_US);
fixture.detectChanges();
page.to('#a').openContextMenu(1);
expect(document.querySelector('[data-type="close"]')!.textContent).toBe(en_US.reuseTab.close);
}));
});
class PageObject {
constructor() {
this.to('#a');
}
tap(cb: () => void): this {
cb();
return this;
}
get time(): string {
return this.getEl('#time').innerHTML.trim();
}
getEl(cls: string): HTMLElement {
return dl.query(By.css(cls)).nativeElement as HTMLElement;
}
cd(time: number = 101): this {
fixture.detectChanges();
tick(time);
fixture.detectChanges();
return this;
}
to(id: string): this {
this.getEl(id).click();
this.cd();
return this;
}
get list(): ReuseItem[] {
return rtComp.list;
}
get count(): number {
return this.list.length;
}
expectCount(count: number): this {
expect(page.count).toBe(count);
return this;
}
expectUrl(pos: number, url: string): this {
expect(this.list[pos].url).toBe(url);
return this;
}
expectAttr(pos: number, attrName: string, value: any): this {
expect((this.list[pos] as NzSafeAny)[attrName]).toBe(value);
return this;
}
expectActive(pos: number, result: boolean): this {
expect(this.list[pos].active).toBe(result);
return this;
}
expectTime(result: string): this {
expect(this.time).toBe(result);
return this;
}
close(pos: number): this {
const ls = document.querySelectorAll('.anticon-close');
if (pos > ls.length) {
expect(false).toBe(true, `the pos muse be 0-${ls.length}`);
return this;
} else if (ls.length === 0) {
expect(false).toBe(true, `invalid close element`);
return this;
}
(ls[pos] as HTMLElement).click();
return this.cd();
}
go(pos: number): this {
const ls = document.querySelectorAll('.ant-tabs-tab');
if (pos > ls.length) {
expect(false).toBe(true, `the pos muse be 0-${ls.length}`);
return this;
} else if (ls.length === 0) {
expect(false).toBe(true, `invalid item element`);
return this;
}
rtComp._to(pos);
this.cd();
return this;
}
openContextMenu(pos: number, eventArgs?: any): this {
const ls = document.querySelectorAll('.reuse-tab__name');
if (pos > ls.length) {
expect(false).toBe(true, `the pos muse be 0-${ls.length}`);
return this;
}
(ls[pos] as HTMLElement).dispatchEvent(new MouseEvent('contextmenu', eventArgs));
this.cd();
return this;
}
clickContentMenu(type: string): this {
const el = document.querySelector(`.reuse-tab__cm li[data-type="${type}"]`);
expect(el).not.toBeNull(`the ${type} is invalid element of content menu container`);
(el as HTMLElement).click();
return this.cd();
}
end(): void {
flush();
discardPeriodicTasks();
}
}
});
({
selector: 'a-comp',
template: `
<a id="a" [routerLink]="['/a']">a</a>
<a id="b" [routerLink]="['/b/1']">b1</a>
<a id="b2" [routerLink]="['/b/2']">b2</a>
<a id="b3" [routerLink]="['/b/3']">b3</a>
<a id="c" [routerLink]="['/c']">c</a>
<a id="d" [routerLink]="['/d']">d</a>
<a id="e" [routerLink]="['/e']">e</a>
<a id="leave" [routerLink]="['/leave']">leave</a>
<router-outlet></router-outlet>
`,
})
class AppComponent { }
({
template: `
<reuse-tab
#comp
[mode]="mode"
[debug]="debug"
[max]="max"
[debug]="debug"
[excludes]="excludes"
[allowClose]="allowClose"
[keepingScroll]="keepingScroll"
[keepingScrollContainer]="keepingScrollContainer"
[customContextMenu]="customContextMenu"
[tabType]="tabType"
[tabMaxWidth]="tabMaxWidth"
[routeParamMatchMode]="routeParamMatchMode"
(change)="change($event)"
(close)="close($event)"
>
</reuse-tab>
<div id="children"><router-outlet></router-outlet></div>
`,
})
class LayoutComponent {
('comp', { static: true })
comp: ReuseTcomponentsomponent;
mode: ReuseTabMatchMode = ReuseTabMatchMode.URL;
debug = false;
max: number = 3;
excludes: RegExp[] = [];
allowClose = true;
keepingScroll = false;
keepingScrollContainer: Window | Element | string | null = null;
customContextMenu: ReuseCustomContextMenu[] = [];
tabType: 'line' | 'card' = 'line';
tabMaxWidth: number;
routeParamMatchMode: ReuseTabRouteParamMatchMode = 'strict';
change(): void { }
close(): void { }
}
({
selector: 'a-comp',
template: `
a:
<div id="time">{{ time }}</div>
`,
})
class AComponent {
time = +new Date();
_onReuseInit(): void { }
_onReuseDestroy(): void { }
}
({
selector: 'b-comp',
template: `
b:
<div id="time">{{ time }}</div>
<a id="b2" [routerLink]="['/b/2']">b2</a>
<a id="b3" [routerLink]="['/b/3']">b3</a>
`,
})
class BComponent {
time = +new Date();
_onReuseInit(): void { }
_onReuseDestroy(): void { }
}
({
selector: 'c-comp',
template: `
c:
<div id="time">{{ time }}</div>
<a id="to-d" routerLink="/d">to-d</a>
`,
})
class CComponent {
time = +new Date();
constructor(private srv: ReuseTabService) {
this.srv.title = 'new c title';
}
_onReuseInit(): void { }
_onReuseDestroy(): void { }
}
({
selector: 'd-comp',
template: `
d:
<div id="time">{{ time }}</div>
<a id="to-c" routerLink="/c">to-c</a>
`,
})
class DComponent {
time = +new Date();
_onReuseInit(): void { }
_onReuseDestroy(): void { }
}
({
selector: 'e-comp',
template: `
e:
<div id="time">{{ time }}</div>
`,
})
class EComponent {
time = +new Date();
constructor(reuse: ReuseTabService) {
reuse.closable = false;
}
_onReuseInit(): void { }
_onReuseDestroy(): void { }
}