Skip to content

Commit 58e969b

Browse files
committed
Allow inclusion of JavaScript and CSS file paths in the HtmlContentView
This change adds the client-side behavior for new parameters to Set-VSCodeHtmlContentView which allow the user to specify JavaScriptPaths and StyleSheetPaths to include local JavaScript and CSS files into their HTML views. Resolves #910.
1 parent 92bf3ce commit 58e969b

File tree

4 files changed

+65
-8
lines changed

4 files changed

+65
-8
lines changed

examples/Assets/script.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var h1 = document.createElement('h1');
2+
h1.appendChild(document.createTextNode('Hello from JavaScript!'));
3+
document.body.appendChild(h1);

examples/Assets/style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
body {
2+
color: white;
3+
background-color: cornflowerblue;
4+
}

examples/ContentViewTest.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
$params = @{
2+
HtmlBodyContent = "Testing JavaScript and CSS paths..."
3+
JavaScriptPaths = ".\Assets\script.js"
4+
StyleSheetPaths = ".\Assets\style.css"
5+
}
6+
7+
$view = New-VSCodeHtmlContentView -Title "Test View" -ShowInColumn Two
8+
Set-VSCodeHtmlContentView -View $view @params

src/features/CustomViews.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class CustomViewsFeature implements IFeature {
5050
args => {
5151
this.contentProvider.setHtmlContentView(
5252
args.id,
53-
args.htmlBodyContent);
53+
args.htmlContent);
5454
});
5555

5656
languageClient.onRequest(
@@ -119,7 +119,7 @@ class PowerShellContentProvider implements vscode.TextDocumentContentProvider {
119119
)
120120
}
121121

122-
public setHtmlContentView(id: string, content: string) {
122+
public setHtmlContentView(id: string, content: HtmlContent) {
123123
let uriString = this.getUri(id);
124124
let view: CustomView = this.viewIndex[uriString];
125125

@@ -160,7 +160,11 @@ abstract class CustomView {
160160

161161
class HtmlContentView extends CustomView {
162162

163-
private htmlContent: string = "";
163+
private htmlContent: HtmlContent = {
164+
bodyContent: "",
165+
javaScriptPaths: [],
166+
styleSheetPaths: []
167+
};
164168

165169
constructor(
166170
id: string,
@@ -169,17 +173,49 @@ class HtmlContentView extends CustomView {
169173
super(id, title, CustomViewType.HtmlContent);
170174
}
171175

172-
setContent(htmlContent: string) {
176+
setContent(htmlContent: HtmlContent) {
173177
this.htmlContent = htmlContent;
174178
}
175179

176180
appendContent(content: string) {
177-
this.htmlContent += content;
181+
this.htmlContent.bodyContent += content;
178182
}
179183

180184
getContent(): string {
181-
// Return an HTML page which disables JavaScript in content by default
182-
return `<html><head><meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src *; style-src 'self'; script-src 'none';"></head><body>${this.htmlContent}</body></html>`;
185+
var styleSrc = "none";
186+
var styleTags = "";
187+
188+
function getNonce(): number {
189+
return Math.floor(Math.random() * 100000) + 100000;
190+
}
191+
192+
if (this.htmlContent.styleSheetPaths &&
193+
this.htmlContent.styleSheetPaths.length > 0) {
194+
styleSrc = "";
195+
this.htmlContent.styleSheetPaths.forEach(
196+
p => {
197+
var nonce = getNonce();
198+
styleSrc += `'nonce-${nonce}' `;
199+
styleTags += `<link nonce="${nonce}" href="${p}" rel="stylesheet" type="text/css" />\n`;
200+
});
201+
}
202+
203+
var scriptSrc = "none";
204+
var scriptTags = "";
205+
206+
if (this.htmlContent.javaScriptPaths &&
207+
this.htmlContent.javaScriptPaths.length > 0) {
208+
scriptSrc = "";
209+
this.htmlContent.javaScriptPaths.forEach(
210+
p => {
211+
var nonce = getNonce();
212+
scriptSrc += `'nonce-${nonce}' `;
213+
scriptTags += `<script nonce="${nonce}" src="${p}"></script>\n`;
214+
});
215+
}
216+
217+
// Return an HTML page with the specified content
218+
return `<html><head><meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src *; style-src ${styleSrc}; script-src ${scriptSrc};">${styleTags}</head><body>\n${this.htmlContent.bodyContent}\n${scriptTags}</body></html>`;
183219
}
184220
}
185221

@@ -226,9 +262,15 @@ namespace SetHtmlContentViewRequest {
226262
'powerShell/setHtmlViewContent');
227263
}
228264

265+
interface HtmlContent {
266+
bodyContent: string;
267+
javaScriptPaths: string[];
268+
styleSheetPaths: string[];
269+
}
270+
229271
interface SetHtmlContentViewRequestArguments {
230272
id: string;
231-
htmlBodyContent: string;
273+
htmlContent: HtmlContent;
232274
}
233275

234276
namespace AppendHtmlOutputViewRequest {

0 commit comments

Comments
 (0)