Skip to content

Webview with vsc base

Alf Nielsen edited this page Jan 15, 2020 · 7 revisions

Webview example with vsc-base

(Will be updated with more example - last update 2020-01-15)

Webviews are fantastic, and vsc-base try to make it at easy to work with as possible.

Let take a look some examples of how to use it:

vsc-base uses it own template WebviewHTMLTemplate when the body property is used.

The template in combination with the setupWebviewConnection add some easy general setup for a webview:

It adds styling that match the users theme so the webview fills like a part of vsc.

It wraps message passing method between the webview and the extension, and you an easy way the to postMessaing and the little higher version with command based message passing ({command:String, value: any}).

It also do some common functionality for commands like sendSetHTML (Internally this is a command callled vscCommand which will be intercepted in the template).

In the webview it will expose two methods: postMessage and sendCommand the can be used in the html. You can use sendSetHTML with html that includes one of these method. See examples.

So let see some examples:

A simple command based webview:

  const { onCommand, sendSetHTML: set } = vsc.startWebview(context, {
    title: "Rename",
    body: `
      <div class='container'>
         <h2>Ping test</h2>
         <button onClick="sendCommand('ping')">ping</button>
         <pre id='info'>info</pre>
       </div>
    `});
  let count = 1;
  await onCommand(async (command, value, resolve) => {
    switch (command) {
      case "ping":
        set("#info", "Ping!" + count++);
        break;
    }
  });

A custem html webview

sendSetHTML will not really work, but it will send a message {command:'vscCommand',value:'somehtml'}

sendCommand (and onCommand) will work. onCommand intercepts message with a {command:string, value:any} structure, and send message will just send a message with {command:string,value:any})

  const { onMessage, postMessage } = vsc.startWebview(context, {
    title: "Rename",
    html: `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My custom html webview</title>
    <script>
    (function() {
      const vscode = acquireVsCodeApi();
      window.postMessage = vscode.postMessage;
      const onMessageCode = (event) => {
         const data = event.data;
         // do thing something with the message send
      }
      window.addEventListener('message', onMessageCode);
    }())
    </script>
</head>
<body>This is my fully controlled version</body>
</html>    `});
  let count = 1;
  await onMessage(async (message: any) => {
         // do thing something with the message send
  });

Search files in current project example:

Note that it set a color in the style using vscode color variable to match users color theme.

  const { sendSetHTML: set, onCommand, dispose } = vsc.startWebview(context, {
      title: "Search in file",
      style: `pre { background: var(--vscode-input-background); padding: 10px; }`,
      showOptions: 2, // this will open the webview in column 2
      body: `
      Search: <input type='text' onkeyup="sendCommand('search',this.value)" > (Glob search! use ** and *)
      <br>
      <div id='info'>info</div>
      <br>
      <div id='files'></div>
      <br><br>
      <button onClick="sendCommand('close')">Close<button>
    `
   });
   await onCommand(async (command, value, resolve) => {
      switch (command) {
         case "close":
            resolve();
            break;
         case "search":
            const files = await vsc.findFilePaths(value);
            set("#info", 'Found:' + files.length)
            // show first 5 results:
            set("#files", files.slice(0, 5).map(x => `<a href='#' onClick="sendCommand('open','${x}')">${x}</a>`).join('<br/>'));
            break;
         case "open":
            set("#info", `Open: ${value}`)
            await vsc.open(value, 1); // open file in column 1
            break;
      }
   });
   dispose()
   vsc.showMessage("Script Done!");

Load custom html page example:

   const pathToExtensionHtmlFile = vsc.joinPaths(context.extensionPath, 'src/test-webview.html');
   const html = await vsc.getFileContent(pathToExtensionHtmlFile)
   const { onCommand } = vsc.startWebview(context, {
      title: "Html Webview",
      html
   });
   await onCommand(async (command, value, resolve) => {
      switch (command) {
         case "info":
            vsc.showMessage(value);
            break;
      }
   });

Used as a simple display/log (No interaction)

This will create a webview (the script/extension will continue, and not wait for any interaction)

  vsc.startWebview(context, {
      title: "Log some data",
      style: `.error { color: red } .warning { color: orange }`,
      showOptions: 2, // this will open the webview in column 2
      body: `
      <h3>Log:</h3>
      ${logs.map(l=>{
         let _class = l.error ? 'error' ? l.warning ? 'warning' : '' 
         return `<div>[${l.time}] <span class='${_class}'>${l.message}</span></div>`
      })}
    `
   });
Clone this wiki locally