Skip to content

Commit 4efacd1

Browse files
#203 refactored data preview webview panel init and loading for new vscode webview uris and CSP
1 parent 0435277 commit 4efacd1

File tree

3 files changed

+44
-37
lines changed

3 files changed

+44
-37
lines changed

.eslintrc.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"@typescript-eslint"
1010
],
1111
"rules": {
12-
"@typescript-eslint/class-name-casing": "warn",
1312
"@typescript-eslint/semi": "warn",
1413
"curly": "warn",
1514
"eqeqeq": "warn",

src/data.preview.ts

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,8 @@ export class DataPreview {
174174
this._logger.debug(`(): creating data.preview... \n theme: '${this.theme}' \n charts: '${this._charts}' \
175175
\n dataUrl:`, this._dataUrl);
176176

177-
// create html template for data preview with local scripts, styles and theme params replaced
178-
const scriptsPath: string = Uri.file(path.join(this._extensionPath, 'web/scripts'))
179-
.with({scheme: 'vscode-resource'}).toString(true);
180-
const stylesPath: string = Uri.file(path.join(this._extensionPath, 'web/styles'))
181-
.with({scheme: 'vscode-resource'}).toString(true);
182-
this._html = htmlTemplate.replace({
183-
title: this._fileName,
184-
scripts: scriptsPath,
185-
styles: stylesPath,
186-
theme: this._theme,
187-
themeColor: this.themeColor,
188-
charts: this._charts
189-
});
190-
191177
// initialize webview panel
192-
this._panel = panel;
193-
this.initWebview(viewType, viewColumn);
178+
this._panel = this.initWebview(viewType, viewColumn, panel, htmlTemplate);
194179
this.configure();
195180
} // end of constructor()
196181

@@ -235,22 +220,44 @@ export class DataPreview {
235220
* Initializes data preview webview panel.
236221
* @param viewType Preview webview type, i.e. data.preview.
237222
* @param viewColumn vscode IDE view column to display preview in.
223+
* @param viewPanel Optional web view panel to initialize.
224+
* @param template Webview html template.
238225
*/
239-
private initWebview(viewType: string, viewColumn: ViewColumn): void {
240-
if (!this._panel) {
226+
private initWebview(viewType: string,
227+
viewColumn: ViewColumn,
228+
viewPanel: WebviewPanel | undefined,
229+
template: Template
230+
): WebviewPanel {
231+
232+
if (!viewPanel) {
241233
// create new webview panel
242-
this._panel = window.createWebviewPanel(viewType, this._fileName, viewColumn, this.getWebviewOptions());
243-
this._panel.iconPath = Uri.file(path.join(this._extensionPath, './images/data-preview.svg'));
234+
viewPanel = window.createWebviewPanel(viewType, this._fileName, viewColumn, this.getWebviewOptions());
235+
viewPanel.iconPath = Uri.file(path.join(this._extensionPath, './images/data-preview.svg'));
244236
}
237+
238+
// create html template for data preview with local scripts, styles and theme params replaced
239+
const scriptsPath: string = viewPanel.webview.asWebviewUri(
240+
Uri.file(path.join(this._extensionPath, 'web/scripts'))).toString(true);
241+
const stylesPath: string = viewPanel.webview.asWebviewUri(
242+
Uri.file(path.join(this._extensionPath, 'web/styles'))).toString(true);
243+
this._html = template?.replace({
244+
cspSource: viewPanel.webview.cspSource,
245+
title: this._fileName,
246+
scripts: scriptsPath,
247+
styles: stylesPath,
248+
theme: this._theme,
249+
themeColor: this.themeColor,
250+
charts: this._charts
251+
});
245252
this._logger.debug('initWebview(): data.view created!');
246253

247254
// dispose preview panel handler
248-
this._panel.onDidDispose(() => {
255+
viewPanel.onDidDispose(() => {
249256
this.dispose();
250257
}, null, this._disposables);
251258

252259
// handle view state changes
253-
this._panel.onDidChangeViewState(
260+
viewPanel.onDidChangeViewState(
254261
(viewStateEvent: WebviewPanelOnDidChangeViewStateEvent) => {
255262
let active = viewStateEvent.webviewPanel.visible;
256263
if (!active) {
@@ -267,13 +274,14 @@ export class DataPreview {
267274

268275
// load matching view config, if available
269276
const viewConfigFilePath:string = this._dataUrl.replace(this._fileExtension, '.config');
270-
if (!this._isRemoteData && !this._viewConfig.hasOwnProperty('view') && // is a blank view config
271-
fs.existsSync(viewConfigFilePath)) {
277+
if (!this._isRemoteData &&
278+
!this._viewConfig.hasOwnProperty('view') && // is a blank view config
279+
fs.existsSync(viewConfigFilePath)) {
272280
this.loadConfigFromFile(viewConfigFilePath, false, false); // don't refresh data, don't show errors
273281
}
274282

275283
// process web view messages
276-
this.webview.onDidReceiveMessage(message => {
284+
viewPanel.webview.onDidReceiveMessage(message => {
277285
switch (message.command) {
278286
case 'getDataInfo':
279287
// post initial data view info
@@ -320,6 +328,8 @@ export class DataPreview {
320328
break;
321329
}
322330
}, null, this._disposables);
331+
332+
return viewPanel;
323333
} // end of initWebview()
324334

325335
/**
@@ -342,7 +352,7 @@ export class DataPreview {
342352
const localResourceRoots: Uri[] = [];
343353
const workspaceFolder: WorkspaceFolder = workspace.getWorkspaceFolder(this.uri);
344354
if (workspaceFolder && workspaceFolder !== undefined) {
345-
localResourceRoots.push(Uri.file(workspaceFolder.uri.fsPath));
355+
localResourceRoots.push(workspaceFolder.uri);
346356
}
347357
else if (!this.uri.scheme || this.uri.scheme === 'file') {
348358
localResourceRoots.push(Uri.file(path.dirname(this.uri.fsPath)));
@@ -419,10 +429,9 @@ export class DataPreview {
419429
private async openFile() {
420430
// display open file dialog
421431
let openFolderUri: Uri = Uri.parse(this._dataUrl).with({scheme: 'file'});
422-
const workspaceFolders: Array<WorkspaceFolder> = workspace.workspaceFolders;
423-
if (workspaceFolders && workspaceFolders.length >= 1) {
432+
if (workspace.workspaceFolders && workspace.workspaceFolders.length >= 1) {
424433
// change open file folder uri to the 1st workspace folder, usuallay workspace root
425-
openFolderUri = workspaceFolders[0].uri;
434+
openFolderUri = workspace.workspaceFolders[0].uri;
426435
}
427436
const selectedFiles: Array<Uri> = await window.showOpenDialog({
428437
defaultUri: openFolderUri,
@@ -746,8 +755,7 @@ export class DataPreview {
746755

747756
// create full data file path for saving data
748757
let dataFilePath: string = path.dirname(this._uri.fsPath);
749-
const workspaceFolders: Array<WorkspaceFolder> = workspace.workspaceFolders;
750-
if (this._isRemoteData && workspaceFolders && workspaceFolders.length > 0) {
758+
if (this._isRemoteData && workspace.workspaceFolders && workspace.workspaceFolders.length > 0) {
751759
// use 'rootPath' workspace folder for saving remote data file
752760
dataFilePath = workspace.workspaceFolders[0].uri.fsPath;
753761
}

web/data.view.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
<meta charset="utf-8">
55
<meta http-equiv="X-UA-Compatible" content="IE=edge">
66
<meta http-equiv="Content-Security-Policy"
7-
content="default-src * vscode-resource: https: 'unsafe-inline' 'unsafe-eval';
8-
script-src vscode-resource: blob: data: https: 'unsafe-inline' 'unsafe-eval';
9-
style-src vscode-resource: https: 'unsafe-inline';
10-
img-src vscode-resource: data: https:;
11-
connect-src vscode-resource: blob: data: https: http:;">
7+
content="default-src * {cspSource} https: 'unsafe-inline' 'unsafe-eval';
8+
script-src {cspSource} blob: data: https: 'unsafe-inline' 'unsafe-eval';
9+
style-src {cspSource} https: 'unsafe-inline';
10+
img-src {cspSource} data: https:;
11+
connect-src {cspSource} blob: data: https: http:;">
1212
<meta name="viewport" content="width=device-width, initial-scale=1.0">
1313
<meta name="description" content="Data Preview">
1414
<base href="https://github.com/RandomFractals/vscode-data-preview" target="_blank" />

0 commit comments

Comments
 (0)