mirror of https://github.com/abpframework/abp.git
3 changed files with 159 additions and 0 deletions
@ -1,2 +1,3 @@ |
|||
export * from './cross-origin.strategy'; |
|||
export * from './dom.strategy'; |
|||
export * from './loading.strategy'; |
|||
|
|||
@ -0,0 +1,68 @@ |
|||
import { Observable, of } from 'rxjs'; |
|||
import { switchMap } from 'rxjs/operators'; |
|||
import { fromLazyLoad } from '../utils'; |
|||
import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from './cross-origin.strategy'; |
|||
import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; |
|||
|
|||
export abstract class LoadingStrategy<T extends HTMLScriptElement | HTMLLinkElement = any> { |
|||
constructor( |
|||
public path: string, |
|||
protected domStrategy: DomStrategy = DOM_STRATEGY.AppendToHead(), |
|||
protected crossOriginStrategy: CrossOriginStrategy = CROSS_ORIGIN_STRATEGY.Anonymous(), |
|||
) {} |
|||
|
|||
abstract createElement(): T; |
|||
|
|||
createStream<T extends Event>(): Observable<T> { |
|||
return of(null).pipe( |
|||
switchMap(() => |
|||
fromLazyLoad<T>(this.createElement(), this.domStrategy, this.crossOriginStrategy), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
|
|||
export class ScriptLoadingStrategy extends LoadingStrategy<HTMLScriptElement> { |
|||
constructor(src: string, domStrategy?: DomStrategy, crossOriginStrategy?: CrossOriginStrategy) { |
|||
super(src, domStrategy, crossOriginStrategy); |
|||
} |
|||
|
|||
createElement(): HTMLScriptElement { |
|||
const element = document.createElement('script'); |
|||
element.src = this.path; |
|||
|
|||
return element; |
|||
} |
|||
} |
|||
|
|||
export class StyleLoadingStrategy extends LoadingStrategy<HTMLLinkElement> { |
|||
constructor(href: string, domStrategy?: DomStrategy, crossOriginStrategy?: CrossOriginStrategy) { |
|||
super(href, domStrategy, crossOriginStrategy); |
|||
} |
|||
|
|||
createElement(): HTMLLinkElement { |
|||
const element = document.createElement('link'); |
|||
element.rel = 'stylesheet'; |
|||
element.href = this.path; |
|||
|
|||
return element; |
|||
} |
|||
} |
|||
|
|||
export const LOADING_STRATEGY = { |
|||
AppendAnonymousScriptToBody(src: string) { |
|||
return new ScriptLoadingStrategy(src, DOM_STRATEGY.AppendToBody()); |
|||
}, |
|||
AppendAnonymousScriptToHead(src: string) { |
|||
return new ScriptLoadingStrategy(src); |
|||
}, |
|||
AppendAnonymousStyleToHead(src: string) { |
|||
return new StyleLoadingStrategy(src); |
|||
}, |
|||
PrependAnonymousScriptToHead(src: string) { |
|||
return new ScriptLoadingStrategy(src, DOM_STRATEGY.PrependToHead()); |
|||
}, |
|||
PrependAnonymousStyleToHead(src: string) { |
|||
return new StyleLoadingStrategy(src, DOM_STRATEGY.PrependToHead()); |
|||
}, |
|||
}; |
|||
@ -0,0 +1,90 @@ |
|||
import { |
|||
CROSS_ORIGIN_STRATEGY, |
|||
DOM_STRATEGY, |
|||
LOADING_STRATEGY, |
|||
ScriptLoadingStrategy, |
|||
StyleLoadingStrategy, |
|||
} from '../strategies'; |
|||
|
|||
const path = 'http://example.com/'; |
|||
|
|||
describe('ScriptLoadingStrategy', () => { |
|||
describe('#createElement', () => { |
|||
it('should return a script element with src attribute', () => { |
|||
const strategy = new ScriptLoadingStrategy(path); |
|||
const element = strategy.createElement(); |
|||
|
|||
expect(element.tagName).toBe('SCRIPT'); |
|||
expect(element.src).toBe(path); |
|||
}); |
|||
}); |
|||
|
|||
describe('#createStream', () => { |
|||
it('should use given dom and cross-origin strategies', done => { |
|||
const domStrategy = DOM_STRATEGY.PrependToHead(); |
|||
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials(); |
|||
|
|||
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => { |
|||
setTimeout(() => { |
|||
el.onload(new CustomEvent('success', { detail: el.crossOrigin })); |
|||
}, 0); |
|||
}) as any; |
|||
|
|||
const strategy = new ScriptLoadingStrategy(path, domStrategy, crossOriginStrategy); |
|||
|
|||
strategy.createStream<CustomEvent>().subscribe(event => { |
|||
expect(event.detail).toBe('use-credentials'); |
|||
done(); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
describe('StyleLoadingStrategy', () => { |
|||
describe('#createElement', () => { |
|||
it('should return a style element with href and rel attributes', () => { |
|||
const strategy = new StyleLoadingStrategy(path); |
|||
const element = strategy.createElement(); |
|||
|
|||
expect(element.tagName).toBe('LINK'); |
|||
expect(element.href).toBe(path); |
|||
expect(element.rel).toBe('stylesheet'); |
|||
}); |
|||
}); |
|||
|
|||
describe('#createStream', () => { |
|||
it('should use given dom and cross-origin strategies', done => { |
|||
const domStrategy = DOM_STRATEGY.PrependToHead(); |
|||
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials(); |
|||
|
|||
domStrategy.insertElement = jest.fn((el: HTMLLinkElement) => { |
|||
setTimeout(() => { |
|||
el.onload(new CustomEvent('success', { detail: el.crossOrigin })); |
|||
}, 0); |
|||
}) as any; |
|||
|
|||
const strategy = new StyleLoadingStrategy(path, domStrategy, crossOriginStrategy); |
|||
|
|||
strategy.createStream<CustomEvent>().subscribe(event => { |
|||
expect(event.detail).toBe('use-credentials'); |
|||
done(); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
describe('LOADING_STRATEGY', () => { |
|||
test.each` |
|||
name | Strategy | domStrategy |
|||
${'AppendAnonymousScriptToBody'} | ${ScriptLoadingStrategy} | ${'AppendToBody'} |
|||
${'AppendAnonymousScriptToHead'} | ${ScriptLoadingStrategy} | ${'AppendToHead'} |
|||
${'AppendAnonymousStyleToHead'} | ${StyleLoadingStrategy} | ${'AppendToHead'} |
|||
${'PrependAnonymousScriptToHead'} | ${ScriptLoadingStrategy} | ${'PrependToHead'} |
|||
${'PrependAnonymousStyleToHead'} | ${StyleLoadingStrategy} | ${'PrependToHead'} |
|||
`(
|
|||
'should successfully map $name to $Strategy.name with $domStrategy dom strategy', |
|||
({ name, Strategy, domStrategy }) => { |
|||
expect(LOADING_STRATEGY[name](path)).toEqual(new Strategy(path, DOM_STRATEGY[domStrategy]())); |
|||
}, |
|||
); |
|||
}); |
|||
Loading…
Reference in new issue