Skip to content

Commit ee49f47

Browse files
authored
Use webview toolkit in Documatic panel (#1074)
1 parent 85fac73 commit ee49f47

File tree

4 files changed

+78
-202
lines changed

4 files changed

+78
-202
lines changed

src/commands/documaticPreviewPanel.ts

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export class DocumaticPreviewPanel {
2020
private static readonly viewType = "isc-documatic-preview";
2121

2222
private readonly _panel: vscode.WebviewPanel;
23-
private readonly _webviewFolderUri: vscode.Uri;
2423
private _disposables: vscode.Disposable[] = [];
2524

2625
/** The `TextEditor` of the class document that we're previewing documentation for. */
@@ -89,7 +88,6 @@ export class DocumaticPreviewPanel {
8988

9089
private constructor(panel: vscode.WebviewPanel, webviewFolderUri: vscode.Uri, editor: vscode.TextEditor) {
9190
this._panel = panel;
92-
this._webviewFolderUri = webviewFolderUri;
9391
this._editor = editor;
9492

9593
// Update the panel's icon
@@ -99,7 +97,7 @@ export class DocumaticPreviewPanel {
9997
};
10098

10199
// Set the webview's initial content
102-
this.setWebviewHtml();
100+
this.setWebviewHtml(webviewFolderUri);
103101

104102
// Register handlers
105103
this.registerEventHandlers();
@@ -119,47 +117,92 @@ export class DocumaticPreviewPanel {
119117
/**
120118
* Set the static html for the webview.
121119
*/
122-
private setWebviewHtml() {
123-
const webview = this._panel.webview;
124-
125-
// Local path to script and css for the webview
126-
const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._webviewFolderUri, "documaticPreview.js"));
127-
const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this._webviewFolderUri, "documaticPreview.css"));
128-
129-
// Use a nonce to whitelist which scripts can be run
130-
const nonce = (function () {
131-
let text = "";
132-
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
133-
for (let i = 0; i < 32; i++) {
134-
text += possible.charAt(Math.floor(Math.random() * possible.length));
135-
}
136-
return text;
137-
})();
120+
private setWebviewHtml(webviewFolderUri: vscode.Uri) {
121+
// Get the path to the @vscode/webview-ui-toolkit minimized js
122+
const toolkitUri = this._panel.webview.asWebviewUri(vscode.Uri.joinPath(webviewFolderUri, "toolkit-1.2.1.min.js"));
138123

139124
// Set the webview's html
140125
this._panel.webview.html = `
141126
<!DOCTYPE html>
142127
<html lang="en-us">
143128
<head>
144129
<meta charset="UTF-8">
145-
146-
<!--
147-
Use a content security policy to only allow loading images from https or from our extension directory,
148-
and only allow scripts that have a specific nonce.
149-
-->
150-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webview.cspSource}; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
151-
152-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
153-
154-
<link href="${styleUri}" rel="stylesheet">
130+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
131+
<script type="module" src="${toolkitUri}"></script>
155132
</head>
156133
<body>
157-
<br>
158-
<h2 id="header"></h2>
159-
<br>
134+
<h1 id="header"></h1>
135+
<vscode-divider></vscode-divider>
160136
<div id="showText"></div>
161-
162-
<script nonce="${nonce}" src="${scriptUri}"></script>
137+
<script>
138+
const vscode = acquireVsCodeApi();
139+
const header = document.getElementById("header");
140+
const showText = document.getElementById("showText");
141+
const memberregex = new RegExp(
142+
"(?:<method>([^<>/]*)</method>)|(?:<property>([^<>/]*)</property>)|(?:<query>([^<>/]*)</query>)",
143+
"gi"
144+
);
145+
let classUri;
146+
147+
// Handle messages sent from the extension to the webview
148+
window.addEventListener("message", (event) => {
149+
const message = event.data; // The json data that the extension sent
150+
151+
// Update the header to reflect what we're previewing
152+
header.innerText = message.element;
153+
154+
// Update the uri of the class that we're previewing
155+
classUri = message.uri;
156+
157+
// Modify the Documatic HTML for previewing and show it
158+
let modifiedDesc = message.desc;
159+
let matcharr;
160+
while ((matcharr = memberregex.exec(message.desc)) !== null) {
161+
let commandArgs = [classUri];
162+
if (matcharr[1] !== undefined) {
163+
// This is a <METHOD> HTML tag
164+
commandArgs[1] = "method";
165+
commandArgs[2] = matcharr[1];
166+
} else if (matcharr[2] !== undefined) {
167+
// This is a <PROPERTY> HTML tag
168+
commandArgs[1] = "property";
169+
commandArgs[2] = matcharr[2];
170+
} else {
171+
// This is a <QUERY> HTML tag
172+
commandArgs[1] = "query";
173+
commandArgs[2] = matcharr[3];
174+
}
175+
const href = "command:intersystems.language-server.showSymbolInClass?" + encodeURIComponent(JSON.stringify(commandArgs));
176+
const title = "Go to this " + commandArgs[1] + " definition";
177+
modifiedDesc = modifiedDesc.replace(matcharr[0], '<a href="' + href + '" title="' + title + '">' + commandArgs[2] + '</a>');
178+
}
179+
showText.innerHTML = modifiedDesc
180+
.replace(/<class>|<parameter>/gi, "<b><i>")
181+
.replace(/<\\/class>|<\\/parameter>/gi, "</i></b>")
182+
.replace(/<pre>/gi, "<code><pre>")
183+
.replace(/<\\/pre>/gi, "</pre></code>")
184+
.replace(/<example(?: +language *= *"?[a-z]+"?)? *>/gi, "<br/><code><pre>")
185+
.replace(/<\\/example>/gi, "</pre></code>");
186+
187+
// Then persist state information.
188+
// This state is returned in the call to vscode.getState below when a webview is reloaded.
189+
vscode.setState({
190+
header: header.innerText,
191+
showText: showText.innerHTML,
192+
uri: classUri,
193+
});
194+
});
195+
196+
// Webviews are normally torn down when not visible and re-created when they become visible again.
197+
// State lets us save information across these re-loads
198+
const state = vscode.getState();
199+
if (state) {
200+
// Fill in webview from the cache
201+
header.innerText = state.header;
202+
showText.innerHTML = state.showText;
203+
classUri = state.uri;
204+
}
205+
</script>
163206
</body>
164207
</html>`;
165208
}

src/commands/restDebugPanel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export class RESTDebugPanel {
107107
vscode.window.showErrorMessage("No REST web applications are configured in the server's namespace.", "Dismiss");
108108
return;
109109
}
110-
//restWebApps.push("aaaaaafffffffffffffffffffffffffff","Kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk","b","c","d","e","f","g","h","i");
110+
111111
if (this.currentPanel !== undefined) {
112112
// Can only have one panel open at once
113113
if (!this.currentPanel._panel.visible) {

webview/documaticPreview.css

Lines changed: 0 additions & 91 deletions
This file was deleted.

webview/documaticPreview.js

Lines changed: 0 additions & 76 deletions
This file was deleted.

0 commit comments

Comments
 (0)