Skip to content

Commit

Permalink
inject webview-events.js script into preview html (#5766)
Browse files Browse the repository at this point in the history
## Summary

- addresses #4276
- page load detection, title display for HTML files, copy/paste, back/forward navigation, etc. should now work in the Viewer in Positron Server Web / Positron on Workbench

### Release Notes

#### New Features

- Support page load detection, title display for HTML files, copy-paste, back/forward navigation, page refresh, etc. in the Viewer for Positron Server Web / Positron on Workbench (#4276)

#### Bug Fixes

- N/A

## Implementation

Mainly, I used the "Create some sort of proxy layer of our own to inject the script" idea from #4276, with a bit of "[Run away from home and live in the woods](https://www.wikihow.com/Run-Away-from-Home-and-Live-in-the-Woods)" sprinkled in the process.

### Positron Proxy
- We now have a `scripts_preview.html` file that serves a similar purpose for the Viewer as the `scripts_help.html` for the Help Pane, which is used as a "template" to inject resources like styles and scripts into the HTML content being presented in the Viewer
- In particular, we inject the `webview-events.js` script (see extensions/positron-proxy/resources/webview-events.js) into this template. The webview-events.js script is a copy of the existing Electron version of the script (see src/vs/workbench/contrib/webview/browser/pre/webview-events.js), with a couple modifications for running in a Web context.  Changes are fenced between `// --- Start Positron Proxy Changes ---` and `// --- End Positron Proxy Changes ---` comments.
- The HTMLProxy does this injection only when we are running in Web, so that we don't interfere with the Electron webview-events.js script that is injected from the core Positron code.
- Refactored Positron Proxy to load and inject Help or Preview resources, move util functions into the util.ts file and type-related declarations to a types.ts file.
- Moved all content rewriting functions to util.ts

### Webview land
- updated `previewOverlayWebview.ts:loadUri()` to align more closely with the HTML structure of src/vs/workbench/contrib/positronHelp/browser/resources/help.html
- the HTML script in `previewOverlayWebview.ts:loadUri()` no longer handles reload/navigation and instead forwards messages along to the Webview or the iframe containing the content as applicable
    - when forwarding messages to the Webview, the flag `__positron_preview_message` is passed
- added some handling to the `onmessage` handler in `webviewElement.ts` to unwrap messages flagged with `__positron_preview_message` and pass them to the appropriate handlers

### HTML Nesting Structure

Here's a summary of the HTML nesting situation, with some pseudo-HTML.

```html
<iframe from={vs/workbench/contrib/webview/browser/pre/index.html}>
    <iframe title="Positron Preview" id="active-frame" from={src/vs/workbench/contrib/webview/browser/pre/fake.html}>
        <body from={src/vs/workbench/contrib/positronPreview/browser/previewOverlayWebview.ts:loadUri()}>
            <iframe id="preview-iframe" title="Preview Content" src={POSITRON_PROXY_URL_OR_HTML_FILE_PATH}>
                <head>
                    <style id="preview-style-defaults" from={extensions/positron-proxy/resources/scripts_preview.html}></style>
                    <style id="preview-style-overrides" from={extensions/positron-proxy/resources/scripts_preview.html}></style>
                    <script id="preview-script" from={extensions/positron-proxy/resources/scripts_preview.html}>
                        {CONTENTS OF extensions/positron-proxy/resources/webview-events.js}
                    </script>
                </head>
                <body>{HTML CONTENT OF FILE IN VIEWER}</body>
            </iframe id="preview-iframe" title="Preview Content" src={POSITRON_PROXY_URL_OR_HTML_FILE_PATH}>
            <script from={src/vs/workbench/contrib/positronPreview/browser/previewOverlayWebview.ts:loadUri()}>
                {FORWARD MESSAGES TO 'preview-iframe' OR TO PARENT WEBVIEW}
            </script>
        </body from={src/vs/workbench/contrib/positronPreview/browser/previewOverlayWebview.ts:loadUri()}>
    </iframe title="Positron Preview" id="active-frame" from={src/vs/workbench/contrib/webview/browser/pre/fake.html}>
</iframe from={vs/workbench/contrib/webview/browser/pre/index.html}>
```

## QA Notes

The changes in this PR should only impact the Viewer in Positron Server Web / Workbench.

The following keyboard actions should work:
- Copy/Cut/Paste
- Select All

In the Viewer menu bar, the following buttons should work:
- forward/back navigation buttons
- refresh/reload button
- page title should show for HTML files instead of the HTML file path

### Preview an HTML file directly

1. From the qa-examples-content directory, locate the [OilandGasMetadata.html](https://github.com/posit-dev/qa-example-content/blob/main/workspaces/dash-py-example/data/OilandGasMetadata.html) file
2. Open the HTML file in the Viewer by doing one of the following
    - Right-click on the file in the File Explorer and select "Open in Viewer"
      <img width="463" alt="image" src="https://github.com/user-attachments/assets/e867ba63-00c4-4a18-8f49-d521f6257e20" />
    - Open the file in an editor and click the View eye icon
      <img width="349" alt="image" src="https://github.com/user-attachments/assets/15509935-066b-4534-8723-0071484f93d0" />

#### Things to verify
- The file's title should show in the Viewer bar, instead of the file path
  <img width="438" alt="image" src="https://github.com/user-attachments/assets/3a6bae68-80e2-4662-a06b-ddaf9075296b" />
- Make a change to the `OilandGasMetadata.html` file, save the changes and click the Refresh button in the Viewer. The page in the Viewer should refresh and show the change you made.
  <img width="1085" alt="image" src="https://github.com/user-attachments/assets/41d23de7-d8eb-4c6f-acfe-94223caa7d68" />
- Copy/Cut/Paste/Select All should all work
  <img width="1088" alt="image" src="https://github.com/user-attachments/assets/ee221889-f561-4660-81e2-fa0e7d74dda1" />

### Preview an HTML page being served

Any of the qa-examples-content directory app frameworks should do, but I tested with the [flask_example](https://github.com/posit-dev/qa-example-content/tree/main/workspaces/python_apps/flask_example), as it's easier to test the back/forward navigation and copy/paste keyboard actions.

1. From the qa-examples-content directory, locate the [__init__.py](https://github.com/posit-dev/qa-example-content/blob/main/workspaces/python_apps/flask_example/__init__.py) file
2. Open the `__init__.py` file in an editor
3. Click the Launch App button
   <img width="235" alt="image" src="https://github.com/user-attachments/assets/86f69f22-280b-44a0-a238-fb7310399d60" />

#### Things to verify
- Back/Forward navigation buttons work

    https://github.com/user-attachments/assets/06fcca91-230b-4beb-92c2-f8c53b9a8561

    1. Click on "Registration"
    2. Click on the back arrow -- we should get back to the "Posts" page
    3. Click on the forward arrow -- we should go to the "Registration" page
- Refresh button works

    https://github.com/user-attachments/assets/f7b6d016-8195-45c3-94a7-112e9b88c8fa

    1. Click on "Registration"
    2. Enter some text in one of the input boxes
    3. Click the Viewer refresh button -- input should be cleared

- Copy/Cut/Paste/Select All should all work
  • Loading branch information
sharon-wang authored Jan 9, 2025
1 parent a84eed9 commit a13cbeb
Show file tree
Hide file tree
Showing 12 changed files with 906 additions and 184 deletions.
16 changes: 16 additions & 0 deletions extensions/positron-proxy/resources/scripts_help.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@

<head>
<!--
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
* _ *
* _ __ ___ | |_ ___ _ *
* | '_ \ / _ \ | __| / _ \ (_) *
* | | | | | (_) | | |_ | __/ _ *
* |_| |_| \___/ \__| \___| (_) *
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
Style elements must be in the form:
<style id="identifier">
...
</style>
See getStyleElement in extensions/positron-proxy/src/positronProxy.ts.
-->
<style id="help-style-defaults">
::selection {
Expand Down Expand Up @@ -49,10 +57,18 @@
}
</style>
<!--
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
* _ *
* _ __ ___ | |_ ___ _ *
* | '_ \ / _ \ | __| / _ \ (_) *
* | | | | | (_) | | |_ | __/ _ *
* |_| |_| \___/ \__| \___| (_) *
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
Script elements must be in the form:
<script id="identifier" type="module">
...
</script>
See getScriptElement in extensions/positron-proxy/src/positronProxy.ts.
-->
<script id="help-script" type="module">
// Set the find result.
Expand Down
64 changes: 64 additions & 0 deletions extensions/positron-proxy/resources/scripts_preview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<!--
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
* _ *
* _ __ ___ | |_ ___ _ *
* | '_ \ / _ \ | __| / _ \ (_) *
* | | | | | (_) | | |_ | __/ _ *
* |_| |_| \___/ \__| \___| (_) *
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
Style elements must be in the form:
<style id="identifier">
...
</style>
See getStyleElement in extensions/positron-proxy/src/positronProxy.ts.
-->
<style id="preview-style-defaults">
body {
/* Set the background to white like the default in a web browser */
background: white;
}
</style>
<style id="preview-style-overrides">
::-webkit-scrollbar {
background: transparent;
width: 14px;
height: 14px;
cursor: default !important;
}

::-webkit-scrollbar-track {
opacity: 0;
}

::-webkit-scrollbar-thumb {
min-height: 20px;
background-color: var(--vscode-scrollbarSlider-background);
}

::-webkit-scrollbar-thumb:hover {
cursor: pointer !important;
background-color: var(--vscode-scrollbarSlider-hoverBackground);
}
</style>
<!--
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
* _ *
* _ __ ___ | |_ ___ _ *
* | '_ \ / _ \ | __| / _ \ (_) *
* | | | | | (_) | | |_ | __/ _ *
* |_| |_| \___/ \__| \___| (_) *
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
Script elements must be in the form:
<script id="identifier" type="module">
...
</script>
See getScriptElement in extensions/positron-proxy/src/positronProxy.ts.
-->
<script id="preview-script" type="module">// webviewEventsScript placeholder</script>
</head>

<body></body>
</html>
Loading

0 comments on commit a13cbeb

Please sign in to comment.