@@ -25,11 +25,71 @@ export abstract class WebView {
2525 private _disposables : Disposable [ ] = [ ] ;
2626 private _onDispose : ( ) => void ;
2727
28+ public constructor (
29+ protected readonly extensionUri : Uri ,
30+ protected readonly title : string ,
31+ ) { }
32+
2833 set onDispose ( disposeCallback : ( ) => void ) {
2934 this . _onDispose = disposeCallback ;
3035 }
3136
32- abstract render ( ) : WebView ;
37+ abstract body ( ) : string ;
38+ abstract l10nMessages ?( ) : Record < string , string > ;
39+ abstract scripts ?( ) : string [ ] ;
40+ abstract styles ?( ) : string [ ] ;
41+ public render ( ) : WebView {
42+ const policies = [
43+ `default-src 'none';` ,
44+ `font-src ${ this . panel . webview . cspSource } data:;` ,
45+ `img-src ${ this . panel . webview . cspSource } data:;` ,
46+ `script-src ${ this . panel . webview . cspSource } ;` ,
47+ `style-src ${ this . panel . webview . cspSource } ;` ,
48+ ] ;
49+ const styles = ( this ?. styles ( ) || [ ] )
50+ . map (
51+ ( style ) =>
52+ `<link rel="stylesheet" href="${ this . webviewUri (
53+ this . extensionUri ,
54+ style ,
55+ ) } ">`,
56+ )
57+ . join ( "" ) ;
58+ const scripts = ( this ?. scripts ( ) || [ ] )
59+ . map (
60+ ( script ) =>
61+ `<script type="module" src="${ this . webviewUri (
62+ this . extensionUri ,
63+ script ,
64+ ) } "></script>`,
65+ )
66+ . join ( "" ) ;
67+
68+ this . panel . webview . html = `<!DOCTYPE html>
69+ <html lang="en">
70+ <head>
71+ <meta charset="UTF-8" />
72+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
73+ <meta http-equiv="Content-Security-Policy" content="${ policies . join (
74+ " " ,
75+ ) } " />
76+ ${ styles }
77+ <title>${ this . title } </title>
78+ </head>
79+ <body>
80+ ${ this . body ( ) }
81+ ${ scripts }
82+ ${
83+ this ?. l10nMessages
84+ ? `<script type="application/json" id="l10n-messages">${ JSON . stringify ( this ?. l10nMessages ( ) ) } </script>`
85+ : ""
86+ }
87+ </body>
88+ </html>` ;
89+
90+ return this ;
91+ }
92+
3393 abstract processMessage ( event : Event ) : void ;
3494
3595 public withPanel ( webviewPanel : WebviewPanel ) : WebView {
@@ -60,4 +120,54 @@ export abstract class WebView {
60120 Uri . joinPath ( extensionUri , "client" , "dist" , "webview" , name ) ,
61121 ) ;
62122 }
123+
124+ public webviewHtml (
125+ body : string ,
126+ styleSrc ?: string ,
127+ scriptSrc ?: string ,
128+ l10nMessages ?: Record < string , string > ,
129+ ) {
130+ const policies = [
131+ `default-src 'none';` ,
132+ `font-src ${ this . panel . webview . cspSource } data:;` ,
133+ `img-src ${ this . panel . webview . cspSource } data:;` ,
134+ `script-src ${ this . panel . webview . cspSource } ;` ,
135+ `style-src ${ this . panel . webview . cspSource } ;` ,
136+ ] ;
137+ return `<!DOCTYPE html>
138+ <html lang="en">
139+ <head>
140+ <meta charset="UTF-8" />
141+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
142+ <meta http-equiv="Content-Security-Policy" content="${ policies . join (
143+ " " ,
144+ ) } " />
145+ ${
146+ styleSrc
147+ ? `<link rel="stylesheet" href="${ this . webviewUri (
148+ this . extensionUri ,
149+ styleSrc ,
150+ ) } ">`
151+ : ""
152+ }
153+ <title>${ this . title } </title>
154+ </head>
155+ <body>
156+ ${ body }
157+ ${
158+ scriptSrc
159+ ? `<script type="module" src="${ this . webviewUri (
160+ this . extensionUri ,
161+ scriptSrc ,
162+ ) } "></script>`
163+ : ""
164+ }
165+ ${
166+ l10nMessages
167+ ? `<script type="application/json" id="l10n-messages">${ JSON . stringify ( l10nMessages ) } </script>`
168+ : ""
169+ }
170+ </body>
171+ </html>` ;
172+ }
63173}
0 commit comments