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 './cross-origin.strategy'; |
||||
export * from './dom.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