@@ -2,116 +2,118 @@ import * as vscode from 'vscode'
22import * as CR from 'typings'
33import * as path from 'path'
44
5- import getNonce from './utils/nonce'
6- import onReceive from './onReceive'
7-
85/**
96 * Manages React webview panels
107 */
11- class ReactPanel {
12- /**
13- * Track the currently panel. Only allow a single panel to exist at a time.
14- */
15- public static currentPanel :ReactPanel | undefined = undefined
8+ class ReactWebView {
9+ //@ts -ignore
10+ private panel :vscode . WebviewPanel
11+ private extensionPath :string
12+ private disposables :vscode . Disposable [ ] = [ ]
13+ private onReceive :any // TODO: properly type
14+
15+ public constructor ( extensionPath :string ) {
16+ this . extensionPath = extensionPath
17+
18+ // Create and show a new webview panel
19+ this . panel = this . createWebviewPanel ( vscode . ViewColumn . One )
1620
17- private readonly _panel :vscode . WebviewPanel
18- private readonly _extensionPath :string
19- private _disposables :vscode . Disposable [ ] = [ ]
21+ // Set the webview's initial html content
22+ this . panel . webview . html = this . getHtmlForWebview ( )
2023
21- public static async createOrShow ( extensionPath :string ) :Promise < void > {
22- // const hasActiveEditor = vscode.window.activeTextEditor
24+ // Listen for when the panel is disposed
25+ // This happens when the user closes the panel or when the panel is closed programatically
26+ this . panel . onDidDispose ( ( ) => this . dispose ( ) , null , this . disposables )
2327
24- // if (!hasActiveEditor) {
25- // throw new Error('Should have an open file on launch')
26- // }
27- const column = vscode . ViewColumn . One
28+ // Handle messages from the webview
29+ const onReceive = ( action :string | CR . Action ) => vscode . commands . executeCommand ( 'coderoad.receive_action' , action )
30+ this . panel . webview . onDidReceiveMessage ( onReceive , null , this . disposables )
31+ console . log ( 'webview loaded' )
32+ }
2833
34+ public async createOrShow ( column :number ) :Promise < void > {
2935// If we already have a panel, show it.
3036// Otherwise, create a new panel.
31- if ( ReactPanel . currentPanel ) {
32- console . log ( '--- HAS CURRENT PANEL --- ' )
33- ReactPanel . currentPanel . _panel . reveal ( column )
37+ if ( this . panel && this . panel . webview ) {
38+ console . log ( 'reveal ' )
39+ this . panel . reveal ( column )
3440} else {
35- ReactPanel . currentPanel = new ReactPanel ( extensionPath , column )
41+ console . log ( 'make new panel' )
42+ this . panel = this . createWebviewPanel ( column )
43+
3644}
3745}
3846
39- private constructor ( extensionPath :string , column :vscode . ViewColumn ) {
40- this . _extensionPath = extensionPath
41-
47+ private createWebviewPanel ( column :number ) :vscode . WebviewPanel {
4248const viewType = 'CodeRoad'
4349const title = 'CodeRoad'
4450const config = {
4551// Enable javascript in the webview
4652enableScripts :true ,
47-
4853// And restric the webview to only loading content from our extension's `media` directory.
49- localResourceRoots :[ vscode . Uri . file ( path . join ( this . _extensionPath , 'build' ) ) ] ,
50-
54+ localResourceRoots :[ vscode . Uri . file ( path . join ( this . extensionPath , 'build' ) ) ] ,
5155// prevents destroying the window when it is in the background
5256retainContextWhenHidden :true ,
5357}
58+ return vscode . window . createWebviewPanel ( viewType , title , column , config )
59+ }
5460
55- // Create and show a new webview panel
56- this . _panel = vscode . window . createWebviewPanel ( viewType , title , column , config )
57-
58- // Set the webview's initial html content
59- this . _panel . webview . html = this . _getHtmlForWebview ( )
60-
61- // Listen for when the panel is disposed
62- // This happens when the user closes the panel or when the panel is closed programatically
63- this . _panel . onDidDispose ( ( ) => this . dispose ( ) , null , this . _disposables )
64-
65- // Handle messages from the webview
66- this . _panel . webview . onDidReceiveMessage ( onReceive , null , this . _disposables )
61+ private getNonce ( ) :string {
62+ let text = ''
63+ const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
64+ for ( let i = 0 ; i < 32 ; i ++ ) {
65+ text += possible . charAt ( Math . floor ( Math . random ( ) * possible . length ) )
66+ }
67+ return text
6768}
6869
6970public async postMessage ( action :CR . Action ) :Promise < void > {
71+ console . log ( 'webview postMessage' )
72+ console . log ( action )
7073// Send a message to the webview webview.
7174// You can send any JSON serializable data.
72- const success = await this . _panel . webview . postMessage ( action )
75+ const success = await this . panel . webview . postMessage ( action )
7376if ( ! success ) {
7477throw new Error ( `Message post failure:${ JSON . stringify ( action ) } ` )
7578}
79+ console . log ( 'postMessage sent' )
7680}
7781
7882public dispose ( ) :void {
79- ReactPanel . currentPanel = undefined
80-
8183// Clean up our resources
82- this . _panel . dispose ( )
84+ this . panel . dispose ( )
8385
84- while ( this . _disposables . length ) {
85- const x = this . _disposables . pop ( )
86+ while ( this . disposables . length ) {
87+ const x = this . disposables . pop ( )
8688if ( x ) {
8789x . dispose ( )
8890}
8991}
9092}
9193
92- private _getHtmlForWebview ( ) :string {
94+ private getHtmlForWebview ( ) :string {
9395
9496// eslint-disable-next-line
95- const manifest = require ( path . join ( this . _extensionPath , 'build' , 'asset-manifest.json' ) )
97+ const manifest = require ( path . join ( this . extensionPath , 'build' , 'asset-manifest.json' ) )
9698const mainScript = manifest . files [ 'main.js' ]
9799// grab first chunk
98100const chunk = Object . keys ( manifest . files ) . filter ( f => f . match ( / ^ s t a t i c \/ j s \/ .+ \. j s $ / ) ) [ 0 ]
99101const chunkScript = manifest . files [ chunk ]
100102const mainStyle = manifest . files [ 'main.css' ]
101103
102- const scriptPathOnDisk = vscode . Uri . file ( path . join ( this . _extensionPath , 'build' , mainScript ) )
104+ const scriptPathOnDisk = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , mainScript ) )
103105const scriptUri = scriptPathOnDisk . with ( { scheme :'vscode-resource' } )
104- const chunkPathOnDisk = vscode . Uri . file ( path . join ( this . _extensionPath , 'build' , chunkScript ) )
106+ const chunkPathOnDisk = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , chunkScript ) )
105107const chunkUri = chunkPathOnDisk . with ( { scheme :'vscode-resource' } )
106- const stylePathOnDisk = vscode . Uri . file ( path . join ( this . _extensionPath , 'build' , mainStyle ) )
108+ const stylePathOnDisk = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , mainStyle ) )
107109const styleUri = stylePathOnDisk . with ( { scheme :'vscode-resource' } )
108110
109111// Use a nonce to whitelist which scripts can be run
110- const nonce = getNonce ( )
111- const nonce2 = getNonce ( )
112- const nonce3 = getNonce ( )
112+ const nonce = this . getNonce ( )
113+ const nonce2 = this . getNonce ( )
114+ const nonce3 = this . getNonce ( )
113115
114- const output = `<!DOCTYPE html>
116+ return `<!DOCTYPE html>
115117<html lang="en">
116118<head>
117119<meta charset="utf-8">
@@ -121,7 +123,7 @@ class ReactPanel {
121123 <link rel="manifest" href="./manifest.json" />
122124<link rel="stylesheet" type="text/css" href="${ styleUri } ">
123125<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-${ nonce } ' 'nonce-${ nonce2 } ' 'nonce-${ nonce3 } '; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
124- <base href="${ vscode . Uri . file ( path . join ( this . _extensionPath , 'build' ) ) . with ( { scheme :'vscode-resource' } ) } /">
126+ <base href="${ vscode . Uri . file ( path . join ( this . extensionPath , 'build' ) ) . with ( { scheme :'vscode-resource' } ) } /">
125127 <style></style>
126128</head>
127129
@@ -133,9 +135,7 @@ class ReactPanel {
133135 <script nonce="${ nonce3 } " src="${ scriptUri } "></script>
134136</body>
135137 </html>`
136- console . log ( output )
137- return output
138138}
139139}
140140
141- export default ReactPanel
141+ export default ReactWebView