11// Copyright (c) jdneo. All rights reserved.
22// Licensed under the MIT license.
33
4- import { commands , Disposable , ExtensionContext , ViewColumn , WebviewPanel , window } from "vscode" ;
4+ import { commands , ViewColumn } from "vscode" ;
55import { leetCodeExecutor } from "../leetCodeExecutor" ;
66import { IProblem } from "../shared" ;
7+ import { ILeetCodeWebviewOption , LeetCodeWebview } from "./LeetCodeWebview" ;
78import { markdownEngine } from "./markdownEngine" ;
89
9- class LeetCodePreviewProvider implements Disposable {
10+ class LeetCodePreviewProvider extends LeetCodeWebview {
1011
11- private context :ExtensionContext ;
1212private node :IProblem ;
13- private panel :WebviewPanel | undefined ;
14-
15- public initialize ( context :ExtensionContext ) :void {
16- this . context = context ;
17- }
13+ private description :IDescription ;
1814
1915public async show ( node :IProblem ) :Promise < void > {
20- // Fetch problem first before creating webview panel
21- const descString :string = await leetCodeExecutor . getDescription ( node ) ;
22-
16+ this . description = this . parseDescription ( await leetCodeExecutor . getDescription ( node ) , node ) ;
2317this . node = node ;
24- if ( ! this . panel ) {
25- this . panel = window . createWebviewPanel ( "leetcode.preview" , "Preview Problem" , ViewColumn . One , {
26- enableScripts :true ,
27- enableCommandUris :true ,
28- enableFindWidget :true ,
29- retainContextWhenHidden :true ,
30- localResourceRoots :markdownEngine . localResourceRoots ,
31- } ) ;
32-
33- this . panel . webview . onDidReceiveMessage ( async ( message :IWebViewMessage ) => {
34- switch ( message . command ) {
35- case "ShowProblem" :{
36- await commands . executeCommand ( "leetcode.showProblem" , this . node ) ;
37- break ;
38- }
39- }
40- } , this , this . context . subscriptions ) ;
41-
42- this . panel . onDidDispose ( ( ) => {
43- this . panel = undefined ;
44- } , null , this . context . subscriptions ) ;
45- }
46-
47- const description :IDescription = this . parseDescription ( descString , node ) ;
48- this . panel . webview . html = this . getWebViewContent ( description ) ;
49- this . panel . title = `${ node . name } : Preview` ;
50- this . panel . reveal ( ViewColumn . One ) ;
18+ this . showWebviewInternal ( ) ;
5119}
5220
53- public dispose ( ) :void {
54- if ( this . panel ) {
55- this . panel . dispose ( ) ;
56- }
57- }
58-
59- private parseDescription ( descString :string , problem :IProblem ) :IDescription {
60- const [
61- /* title */ , ,
62- url , ,
63- /* tags */ , ,
64- /* langs */ , ,
65- category ,
66- difficulty ,
67- likes ,
68- dislikes ,
69- /* accepted */ ,
70- /* submissions */ ,
71- /* testcase */ , ,
72- ...body
73- ] = descString . split ( "\n" ) ;
21+ protected getWebviewOption ( ) :ILeetCodeWebviewOption {
7422return {
75- title :problem . name ,
76- url,
77- tags :problem . tags ,
78- companies :problem . companies ,
79- category :category . slice ( 2 ) ,
80- difficulty :difficulty . slice ( 2 ) ,
81- likes :likes . split ( ": " ) [ 1 ] . trim ( ) ,
82- dislikes :dislikes . split ( ": " ) [ 1 ] . trim ( ) ,
83- body :body . join ( "\n" ) . replace ( / < p r e > \s * ( [ ^ ] + ?) \s * < \/ p r e > / g, "<pre><code>$1</code></pre>" ) ,
23+ viewType :"leetcode.preview" ,
24+ title :`${ this . node . name } : Preview` ,
25+ viewColumn :ViewColumn . One ,
8426} ;
8527}
8628
87- private getWebViewContent ( desc :IDescription ) :string {
88- const mdStyles :string = markdownEngine . getStyles ( ) ;
89- const buttonStyle :string = `
90- <style>
29+ protected getWebviewContent ( ) :string {
30+ const button :{ element :string , script :string , style :string } = {
31+ element :`<button id="solve">Code Now</button>` ,
32+ script :`const button = document.getElementById('solve');
33+ button.onclick = () => vscode.postMessage({
34+ command: 'ShowProblem',
35+ });` ,
36+ style :`<style>
9137 #solve {
9238 position: fixed;
9339 bottom: 1rem;
@@ -104,9 +50,9 @@ class LeetCodePreviewProvider implements Disposable {
10450 #solve:active {
10551 border: 0;
10652 }
107- </style>
108- ` ;
109- const { title, url, category, difficulty, likes, dislikes, body} = desc ;
53+ </style>` ,
54+ } ;
55+ const { title, url, category, difficulty, likes, dislikes, body} = this . description ;
11056const head :string = markdownEngine . render ( `# [${ title } ](${ url } )` ) ;
11157const info :string = markdownEngine . render ( [
11258`| Category | Difficulty | Likes | Dislikes |` ,
@@ -117,7 +63,7 @@ class LeetCodePreviewProvider implements Disposable {
11763`<details>` ,
11864`<summary><strong>Tags</strong></summary>` ,
11965markdownEngine . render (
120- desc . tags
66+ this . description . tags
12167. map ( ( t :string ) => `[\`${ t } \`](https://leetcode.com/tag/${ t } )` )
12268. join ( " | " ) ,
12369) ,
@@ -127,7 +73,7 @@ class LeetCodePreviewProvider implements Disposable {
12773`<details>` ,
12874`<summary><strong>Companies</strong></summary>` ,
12975markdownEngine . render (
130- desc . companies
76+ this . description . companies
13177. map ( ( c :string ) => `\`${ c } \`` )
13278. join ( " | " ) ,
13379) ,
@@ -137,28 +83,67 @@ class LeetCodePreviewProvider implements Disposable {
13783 <!DOCTYPE html>
13884 <html>
13985 <head>
140- ${ mdStyles }
141- ${ buttonStyle }
86+ ${ markdownEngine . getStyles ( ) }
87+ ${ button . style }
14288 </head>
14389 <body>
14490${ head }
14591${ info }
14692${ tags }
14793${ companies }
14894${ body }
149- < button>Code Now</button>
95+ ${ button . element }
15096 <script>
15197 const vscode = acquireVsCodeApi();
152- const button = document.getElementById('solve');
153- button.onclick = () => vscode.postMessage({
154- command: 'ShowProblem',
155- });
98+ ${ button . script }
15699 </script>
157100 </body>
158101 </html>
159102 ` ;
160103}
161104
105+ protected onDidDisposeWebview ( ) :void {
106+ super . onDidDisposeWebview ( ) ;
107+ delete this . node ;
108+ delete this . description ;
109+ }
110+
111+ protected async onDidReceiveMessage ( message :IWebViewMessage ) :Promise < void > {
112+ switch ( message . command ) {
113+ case "ShowProblem" :{
114+ await commands . executeCommand ( "leetcode.showProblem" , this . node ) ;
115+ break ;
116+ }
117+ }
118+ }
119+
120+ private parseDescription ( descString :string , problem :IProblem ) :IDescription {
121+ const [
122+ /* title */ , ,
123+ url , ,
124+ /* tags */ , ,
125+ /* langs */ , ,
126+ category ,
127+ difficulty ,
128+ likes ,
129+ dislikes ,
130+ /* accepted */ ,
131+ /* submissions */ ,
132+ /* testcase */ , ,
133+ ...body
134+ ] = descString . split ( "\n" ) ;
135+ return {
136+ title :problem . name ,
137+ url,
138+ tags :problem . tags ,
139+ companies :problem . companies ,
140+ category :category . slice ( 2 ) ,
141+ difficulty :difficulty . slice ( 2 ) ,
142+ likes :likes . split ( ": " ) [ 1 ] . trim ( ) ,
143+ dislikes :dislikes . split ( ": " ) [ 1 ] . trim ( ) ,
144+ body :body . join ( "\n" ) . replace ( / < p r e > \s * ( [ ^ ] + ?) \s * < \/ p r e > / g, "<pre><code>$1</code></pre>" ) ,
145+ } ;
146+ }
162147}
163148
164149interface IDescription {