mirror of https://github.com/abpframework/abp.git
3 changed files with 163 additions and 0 deletions
@ -1 +1,2 @@ |
|||
export * from './error.handler'; |
|||
export * from './lazy-style.handler'; |
|||
|
|||
@ -0,0 +1,96 @@ |
|||
import { |
|||
getLocaleDirection, |
|||
LazyLoadService, |
|||
LOADING_STRATEGY, |
|||
LocalizationService, |
|||
} from '@abp/ng.core'; |
|||
import { Injectable, Injector } from '@angular/core'; |
|||
import { map, startWith } from 'rxjs/operators'; |
|||
import { BOOTSTRAP } from '../constants/styles'; |
|||
import { LocaleDirection } from '../models/common'; |
|||
import { LAZY_STYLES } from '../tokens/lazy-styles.token'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class LazyStyleHandler { |
|||
private lazyLoad: LazyLoadService; |
|||
private styles: string[]; |
|||
private _dir: LocaleDirection = 'ltr'; |
|||
|
|||
set dir(dir: LocaleDirection) { |
|||
if (dir === this._dir) return; |
|||
|
|||
this.switchCSS(dir); |
|||
this.setHtmlDir(dir); |
|||
this._dir = dir; |
|||
} |
|||
|
|||
get dir(): LocaleDirection { |
|||
return this._dir; |
|||
} |
|||
|
|||
constructor(injector: Injector) { |
|||
this.setStyles(injector); |
|||
this.setLazyLoad(injector); |
|||
this.listenToLanguageChanges(injector); |
|||
} |
|||
|
|||
private getLoadedBootstrap(): LoadedStyle { |
|||
const href = createLazyStyleHref(BOOTSTRAP, this.dir); |
|||
const selector = `[href$="${href}"]`; |
|||
const link = document.querySelector<HTMLLinkElement>(selector); |
|||
return { href, link }; |
|||
} |
|||
|
|||
private listenToLanguageChanges(injector: Injector) { |
|||
const l10n = injector.get(LocalizationService); |
|||
|
|||
// will always listen, no need to unsubscribe
|
|||
l10n.languageChange |
|||
.pipe( |
|||
map(({ payload }) => payload), |
|||
startWith(l10n.currentLang), |
|||
) |
|||
.subscribe(locale => { |
|||
this.dir = getLocaleDirection(locale); |
|||
}); |
|||
} |
|||
|
|||
private setHtmlDir(dir: LocaleDirection) { |
|||
document.querySelector('html').dir = dir; |
|||
} |
|||
|
|||
private setLazyLoad(injector: Injector) { |
|||
this.lazyLoad = injector.get(LazyLoadService); |
|||
const { href, link } = this.getLoadedBootstrap(); |
|||
this.lazyLoad.loaded.set(href, link); |
|||
} |
|||
|
|||
private setStyles(injector: Injector) { |
|||
this.styles = injector.get(LAZY_STYLES, [BOOTSTRAP]); |
|||
} |
|||
|
|||
private switchCSS(dir: LocaleDirection) { |
|||
this.styles.forEach(style => { |
|||
const oldHref = createLazyStyleHref(style, this.dir); |
|||
const newHref = createLazyStyleHref(style, dir); |
|||
|
|||
const strategy = LOADING_STRATEGY.PrependAnonymousStyleToHead(newHref); |
|||
this.lazyLoad.load(strategy).subscribe(() => this.lazyLoad.remove(oldHref)); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
export function createLazyStyleHref(style: string, dir: string): string { |
|||
return style.replace(/{{\s*dir\s*}}/g, dir); |
|||
} |
|||
|
|||
export function initLazyStyleHandler(injector: Injector) { |
|||
return () => new LazyStyleHandler(injector); |
|||
} |
|||
|
|||
interface LoadedStyle { |
|||
href: string; |
|||
link: HTMLLinkElement; |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
import { LazyLoadService, LOADING_STRATEGY, LocalizationService } from '@abp/ng.core'; |
|||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest'; |
|||
import { EMPTY, of } from 'rxjs'; |
|||
import { BOOTSTRAP } from '../constants/styles'; |
|||
import { createLazyStyleHref, initLazyStyleHandler, LazyStyleHandler } from '../handlers'; |
|||
|
|||
const languageChange = of({ payload: 'en' }); |
|||
|
|||
describe('LazyStyleHandler', () => { |
|||
let spectator: SpectatorService<LazyStyleHandler>; |
|||
let handler: LazyStyleHandler; |
|||
let lazyLoad: LazyLoadService; |
|||
|
|||
const createService = createServiceFactory({ |
|||
service: LazyStyleHandler, |
|||
providers: [ |
|||
{ |
|||
provide: LocalizationService, |
|||
useValue: { currentLang: 'en', languageChange }, |
|||
}, |
|||
], |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
handler = spectator.service; |
|||
lazyLoad = handler['lazyLoad']; |
|||
}); |
|||
|
|||
describe('#dir', () => { |
|||
it('should initially be "ltr"', () => { |
|||
expect(handler.dir).toBe('ltr'); |
|||
}); |
|||
|
|||
it('should set bootstrap to rtl', () => { |
|||
const oldHref = createLazyStyleHref(BOOTSTRAP, 'ltr'); |
|||
const newHref = createLazyStyleHref(BOOTSTRAP, 'rtl'); |
|||
lazyLoad.loaded.set(newHref, null); // avoid actual loading
|
|||
const load = jest.spyOn(lazyLoad, 'load'); |
|||
const remove = jest.spyOn(lazyLoad, 'remove'); |
|||
const strategy = LOADING_STRATEGY.PrependAnonymousStyleToHead(newHref); |
|||
|
|||
handler.dir = 'rtl'; |
|||
|
|||
expect(load).toHaveBeenCalledWith(strategy); |
|||
expect(remove).toHaveBeenCalledWith(oldHref); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
describe('initLazyStyleHandler', () => { |
|||
it('should return a LazyStyleHandler factory', () => { |
|||
const generator = (function*() { |
|||
yield undefined; // LAZY_STYLES
|
|||
yield { loaded: new Map() }; // LazyLoadService
|
|||
yield { currentLang: 'en', languageChange: EMPTY }; // LocalizationService
|
|||
})(); |
|||
|
|||
const injector = { |
|||
get: () => generator.next().value as any, |
|||
}; |
|||
const factory = initLazyStyleHandler(injector); |
|||
|
|||
expect(factory()).toBeInstanceOf(LazyStyleHandler); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue