@@ -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 }
0 commit comments