UNPKG

2.83 kBPlain TextView Raw
1/*eslint new-cap:0, padded-blocks:0*/
2import {ViewResources, resource, ViewCompileInstruction} from 'aurelia-templating';
3import {Loader} from 'aurelia-loader';
4import {Container} from 'aurelia-dependency-injection';
5import {relativeToFile} from 'aurelia-path';
6import {DOM, FEATURE} from 'aurelia-pal';
7
8let cssUrlMatcher = /url\((?!['"]data)([^)]+)\)/gi;
9
10function fixupCSSUrls(address: string, css: string) {
11 if (typeof css !== 'string') {
12 throw new Error(`Failed loading required CSS file: ${address}`);
13 }
14 return css.replace(cssUrlMatcher, (match, p1) => {
15 let quote = p1.charAt(0);
16 if (quote === '\'' || quote === '"') {
17 p1 = p1.substr(1, p1.length - 2);
18 }
19 return 'url(\'' + relativeToFile(p1, address) + '\')';
20 });
21}
22
23class CSSResource {
24 /**
25 *@internal
26 */
27 address: string;
28 /**
29 *@internal
30 */
31 _scoped: any;
32 /**
33 *@internal
34 */
35 _global: boolean;
36 /**
37 *@internal
38 */
39 _alreadyGloballyInjected: boolean;
40
41 constructor(address: string) {
42 this.address = address;
43 this._scoped = null;
44 this._global = false;
45 this._alreadyGloballyInjected = false;
46 }
47
48 initialize(container: Container, Target: Function): void {
49 this._scoped = new (Target as any)(this);
50 }
51
52 register(registry: ViewResources, name?: string): void {
53 if (name === 'scoped') {
54 registry.registerViewEngineHooks(this._scoped);
55 } else {
56 this._global = true;
57 }
58 }
59
60 load(container: Container): Promise<CSSResource> {
61 return container.get(Loader)
62 .loadText(this.address)
63 .catch(() => null)
64 .then(text => {
65 text = fixupCSSUrls(this.address, text);
66 this._scoped.css = text;
67 if (this._global) {
68 this._alreadyGloballyInjected = true;
69 DOM.injectStyles(text);
70 }
71 return this;
72 });
73 }
74}
75
76class CSSViewEngineHooks {
77 owner: CSSResource;
78 css: any;
79 _global: boolean;
80 constructor(owner: CSSResource) {
81 this.owner = owner;
82 this.css = null;
83 }
84
85 beforeCompile(content: DocumentFragment, resources: ViewResources, instruction: ViewCompileInstruction): void {
86 if (instruction.targetShadowDOM) {
87 DOM.injectStyles(this.css, content as any, true);
88 } else if (FEATURE.scopedCSS) {
89 let styleNode = DOM.injectStyles(this.css, content as any, true) as Element;
90 styleNode.setAttribute('scoped', 'scoped');
91 } else if (this._global && !this.owner._alreadyGloballyInjected) {
92 DOM.injectStyles(this.css);
93 this.owner._alreadyGloballyInjected = true;
94 }
95 }
96}
97
98export function _createCSSResource(address: string): Function {
99 @resource(new CSSResource(address))
100 class ViewCSS extends CSSViewEngineHooks {}
101 return ViewCSS;
102}