@@ -2,6 +2,11 @@ import * as vscode from "vscode";
22import { AtelierAPI } from "../api" ;
33import { config , FILESYSTEM_SCHEMA } from "../extension" ;
44import { outputChannel } from "../utils" ;
5+ import { DocumentContentProvider } from "../providers/DocumentContentProvider" ;
6+ import { ClassNode } from "../explorer/models/classesNode" ;
7+ import { PackageNode } from "../explorer/models/packageNode" ;
8+ import { RoutineNode } from "../explorer/models/routineNode" ;
9+ import { NodeBase } from "../explorer/models/nodeBase" ;
510
611interface StudioAction extends vscode . QuickPickItem {
712 name : string ;
@@ -13,10 +18,19 @@ class StudioActions {
1318 private api : AtelierAPI ;
1419 private name : string ;
1520
16- public constructor ( uri : vscode . Uri ) {
17- this . uri = uri ;
18- this . name = this . uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
19- this . api = new AtelierAPI ( uri . authority ) ;
21+ public constructor ( uriOrNode : vscode . Uri | PackageNode | ClassNode | RoutineNode ) {
22+ if ( uriOrNode instanceof vscode . Uri ) {
23+ const uri : vscode . Uri = uriOrNode ;
24+ this . uri = uri ;
25+ this . name = this . uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
26+ this . api = new AtelierAPI ( uri . authority ) ;
27+ } else {
28+ const node : NodeBase = uriOrNode ;
29+ this . api = new AtelierAPI ( ) ;
30+ this . name = ( node instanceof PackageNode )
31+ ? node . fullName + ".PKG"
32+ : node . fullName ;
33+ }
2034 }
2135
2236 public processUserAction ( userAction ) : Thenable < any > {
@@ -36,79 +50,133 @@ class StudioActions {
3650 . showWarningMessage ( target , { modal : true } , "Yes" , "No" )
3751 . then ( answer => ( answer === "Yes" ? "1" : answer === "No" ? "0" : "2" ) ) ;
3852 case 2 : // Run a CSP page/Template. The Target is the full url to the CSP page/Template
39- // Open the target URL in a webview
40- const conn = config ( ) . conn ;
41- const column = vscode . window . activeTextEditor
42- ? vscode . window . activeTextEditor . viewColumn
43- : undefined ;
44- const panel = vscode . window . createWebviewPanel (
45- 'studioactionwebview' ,
46- 'CSP Page' ,
47- column || vscode . ViewColumn . One ,
48- {
49- enableScripts : true ,
50- }
51- ) ;
52- panel . webview . html = `
53- <!DOCTYPE html>
54- <html lang="en">
55- <head>
56- <style type="text/css">
57- body, html
58- {
59- margin: 0; padding: 0; height: 100%; overflow: hidden;
60- }
61- #content
62- {
63- position:absolute; left: 0; right: 0; bottom: 0; top: 0px;
64- }
65- </style>
66- </head>
67- <body>
68- <div id="content">
69- <iframe src="http://${ conn . host } :${ conn . port } ${ target } " onLoad="checkForCancelState()" width="100%" height="100%" frameborder="0"></iframe>
70- </div>
71- <script>
72- function checkForCancelState() {
73- var x = document.getElementsByTagName("BODY")[0];
74- console.log(x);
75- }
76- </script>
77- </body>
78- </html>
79- ` ;
80- panel . onDidDispose (
81- ( ) => {
82- // fire a cancel answer if the user closes the webview
83- return "2" ;
84- }
85- ) ;
86- // TODO: use panel.dispose() when the cancel text is sent back in the iframe
87- break ;
88- // throw new Error("Not suppoorted");
53+ return new Promise ( ( resolve ) => {
54+ let answer = "2" ;
55+ const conn = config ( ) . conn ;
56+ const column = vscode . window . activeTextEditor
57+ ? vscode . window . activeTextEditor . viewColumn
58+ : undefined ;
59+ const panel = vscode . window . createWebviewPanel (
60+ "studioactionwebview" ,
61+ "Studio Extension Page" ,
62+ column || vscode . ViewColumn . One ,
63+ {
64+ enableScripts : true ,
65+ }
66+ ) ;
67+ panel . webview . onDidReceiveMessage ( message => {
68+ if ( message . result && message . result === "done" ) {
69+ answer = "1" ;
70+ panel . dispose ( ) ;
71+ }
72+ } ) ;
73+ panel . onDidDispose ( ( ) => resolve ( answer ) ) ;
74+
75+ const url = new URL ( `http://${ conn . host } :${ conn . port } ${ target } ` ) ;
76+ const api = new AtelierAPI ( ) ;
77+ api . actionQuery ( "select %Atelier_v1_Utils.General_GetCSPToken(?) token" , [ url . toString ( ) ] ) . then ( tokenObj => {
78+ const csptoken = tokenObj . result . content [ 0 ] . token ;
79+ url . searchParams . set ( 'CSPCHD' , csptoken ) ;
80+ url . searchParams . set ( 'Namespace' , conn . ns ) ;
81+ panel . webview . html = `
82+ <!DOCTYPE html>
83+ <html lang="en">
84+ <head>
85+ <style type="text/css">
86+ body, html {
87+ margin: 0; padding: 0; height: 100%; overflow: hidden;
88+ background-color: white;
89+ }
90+ #content {
91+ position:absolute; left: 0; right: 0; bottom: 0; top: 0px;
92+ }
93+ </style>
94+ </head>
95+ <body>
96+ <div id="content">
97+ <iframe src="${ url . toString ( ) } " width="100%" height="100%" frameborder="0"></iframe>
98+ </div>
99+ <script>
100+ const vscode = acquireVsCodeApi();
101+ window.addEventListener("message", receiveMessage, false);
102+ function receiveMessage(event) {
103+ vscode.postMessage(event.data);
104+ }
105+ </script>
106+ </body>
107+ </html>
108+ ` ;
109+ } ) ;
110+ } ) ;
89111 case 3 : // Run an EXE on the client.
90112 throw new Error ( "Not suppoorted" ) ;
91113 case 4 : // Insert the text in Target in the current document at the current selection point
92- throw new Error ( "Not suppoorted" ) ;
114+ const editor = vscode . window . activeTextEditor ;
115+ if ( editor ) {
116+ editor . edit ( editBuilder => {
117+ editBuilder . replace ( editor . selection , target ) ;
118+ } ) ;
119+ }
120+ return ;
93121 case 5 : // Studio will open the documents listed in Target
94- throw new Error ( "Not suppoorted" ) ;
122+ target . split ( "," ) . forEach ( element => {
123+ let classname = element ;
124+ let method : string ;
125+ let offset = 0 ;
126+ if ( element . includes ( ":" ) ) {
127+ [ classname , method ] = element . split ( ":" ) ;
128+ if ( method . includes ( "+" ) ) {
129+ offset = + method . split ( "+" ) [ 1 ] ;
130+ method = method . split ( "+" ) [ 0 ] ;
131+ }
132+ }
133+
134+ const splitClassname = classname . split ( "." ) ;
135+ const filetype = splitClassname [ splitClassname . length - 1 ] ;
136+ const isCorrectMethod = ( text : string ) => ( filetype === "cls" )
137+ ? text . match ( "Method " + method )
138+ : text . startsWith ( method )
139+
140+ const uri = DocumentContentProvider . getUri ( classname ) ;
141+ vscode . window . showTextDocument ( uri , { "preview" : false } ) . then ( newEditor => {
142+ if ( method ) {
143+ const document = newEditor . document ;
144+ for ( let i = 0 ; i < document . lineCount ; i ++ ) {
145+ const line = document . lineAt ( i ) ;
146+ if ( isCorrectMethod ( line . text ) ) {
147+ if ( ! line . text . endsWith ( "{" ) ) offset ++ ;
148+ const cursor = newEditor . selection . active ;
149+ const newPosition = cursor . with ( i + offset , 0 ) ;
150+ newEditor . selection = new vscode . Selection ( newPosition , newPosition ) ;
151+ break ;
152+ }
153+ }
154+ }
155+ } ) ;
156+ } ) ;
157+ return ;
95158 case 6 : // Display an alert dialog in Studio with the text from the Target variable.
96159 return vscode . window . showWarningMessage ( target , { modal : true } ) ;
97160 case 7 : // Display a dialog with a textbox and Yes/No/Cancel buttons.
98161 return vscode . window . showInputBox ( {
99162 prompt : target ,
163+ } ) . then ( msg => {
164+ return {
165+ "msg" : ( msg ? msg : "" ) ,
166+ "answer" : ( msg ? 1 : 2 )
167+ }
100168 } ) ;
101169 default :
102170 throw new Error ( "Not suppoorted" ) ;
103171 }
104172 }
105173
106- private userAction ( action , afterUserAction = false , answer = "" , msg = "" ) : Thenable < void > {
174+ private userAction ( action , afterUserAction = false , answer = "" , msg = "" , type = 0 ) : Thenable < void > {
107175 if ( ! action ) {
108176 return ;
109177 }
110- const func = afterUserAction ? "AfterUserAction" : "UserAction" ;
111- const query = `select * from %Atelier_v1_Utils.Extension_${ func } (?, ?, ?, ?) ` ;
178+ const func = afterUserAction ? "AfterUserAction(?, ?, ?, ?, ?) " : "UserAction(?, ?, ?, ?) " ;
179+ const query = `select * from %Atelier_v1_Utils.Extension_${ func } ` ;
112180 let selectedText = "" ;
113181 const editor = vscode . window . activeTextEditor ;
114182 if ( ! editor ) {
@@ -118,8 +186,9 @@ class StudioActions {
118186 selectedText = editor . document . getText ( selection ) ;
119187
120188 const parameters = afterUserAction
121- ? [ "0" , action . id , this . name , answer ]
122- : [ "0" , action . id , this . name , selectedText ] ;
189+ ? [ type . toString ( ) , action . id , this . name , answer , msg ]
190+ : [ type . toString ( ) , action . id , this . name , selectedText ] ;
191+
123192 return vscode . window . withProgress (
124193 {
125194 cancellable : false ,
@@ -129,34 +198,44 @@ class StudioActions {
129198 ( ) =>
130199 this . api
131200 . actionQuery ( query , parameters )
132- . then ( data => data . result . content . pop ( ) )
201+ . then ( data => {
202+ const actionInfo = data . result . content . pop ( ) ;
203+ actionInfo . save = action . save ;
204+ return actionInfo ;
205+ } )
206+ . then ( this . processSaveFlag )
133207 . then ( this . processUserAction )
134208 . then ( answer => {
135209 if ( answer ) {
136- return this . userAction ( action , true , answer ) ;
210+ return ( answer . msg || answer . msg === "" )
211+ ? this . userAction ( action , true , answer . answer , answer . msg , type )
212+ : this . userAction ( action , true , answer , "" , type ) ;
137213 }
138214 } )
139215 . catch ( err => {
216+ console . log ( err ) ;
140217 outputChannel . appendLine ( `Studio Action "${ action . label } " not supported` ) ;
141218 outputChannel . show ( ) ;
142219 } )
143220 ) ;
144221 }
145222
146- private constructMenu ( menu ) : any [ ] {
223+ private constructMenu ( menu , contextOnly = false ) : any [ ] {
147224 return menu
225+ . filter ( menuGroup => ! ( contextOnly && menuGroup . type === "main" ) )
148226 . reduce (
149227 ( list , sub ) =>
150228 list . concat (
151229 sub . items
152230 . filter ( el => el . id !== "" && el . separator == 0 )
153- // .filter(el => el.enabled == 1)
231+ . filter ( el => el . enabled == 1 )
154232 . map ( el => ( {
155233 ...el ,
156234 id : `${ sub . id } ,${ el . id } ` ,
157235 label : el . name . replace ( "&" , "" ) ,
158236 itemId : el . id ,
159237 type : sub . type ,
238+ description : sub . name . replace ( "&" , "" ) ,
160239 } ) )
161240 ) ,
162241 [ ]
@@ -170,19 +249,57 @@ class StudioActions {
170249 } ) ;
171250 }
172251
173- public getMenu ( menuType : string ) : Thenable < any > {
252+ public getMenu ( menuType : string , contextOnly = false ) : Thenable < any > {
253+ let selectedText = "" ;
254+ const editor = vscode . window . activeTextEditor ;
255+ if ( this . uri && editor ) {
256+ const selection = editor . selection ;
257+ selectedText = editor . document . getText ( selection ) ;
258+ }
259+
174260 const query = "select * from %Atelier_v1_Utils.Extension_GetMenus(?,?,?)" ;
175- const parameters = [ menuType , this . name , "" ] ;
261+ const parameters = [ menuType , this . name , selectedText ] ;
176262
177263 return this . api
178264 . actionQuery ( query , parameters )
179265 . then ( data => data . result . content )
180- . then ( this . constructMenu )
266+ . then ( menu => this . constructMenu ( menu , contextOnly ) )
181267 . then ( menuItems => {
182268 return vscode . window . showQuickPick < StudioAction > ( menuItems , { canPickMany : false } ) ;
183269 } )
184270 . then ( action => this . userAction ( action ) ) ;
185271 }
272+
273+ public attemptedEdit ( ) {
274+ const query = "select * from %Atelier_v1_Utils.Extension_GetStatus(?)" ;
275+ this . api . actionQuery ( query , [ this . name ] ) . then ( statusObj => {
276+ const docStatus = statusObj . result . content . pop ( ) ;
277+ // if(!docStatus.editable && docStatus.inSourceControl && !docStatus.isCheckedOut) {
278+ if ( ! docStatus . editable ) {
279+ const attemptedEditAction = {
280+ id : "0" ,
281+ label : "Attempted Edit"
282+ } ;
283+ vscode . commands . executeCommand ( 'undo' ) ;
284+ this . userAction ( attemptedEditAction , false , "" , "" , 1 ) ;
285+ } // else if(!docStatus.editable && docStatus.in)
286+ } ) ;
287+ }
288+
289+ private async processSaveFlag ( userAction ) {
290+ if ( userAction . save ) {
291+ const bitString = userAction . save . toString ( ) . padStart ( 3 , "0" ) ;
292+ // Save the current document
293+ if ( bitString . charAt ( 0 ) === "1" ) {
294+ await vscode . window . activeTextEditor . document . save ( ) ;
295+ }
296+ // Save all documents
297+ if ( bitString . charAt ( 2 ) === "1" ) {
298+ await vscode . workspace . saveAll ( ) ;
299+ }
300+ }
301+ return userAction ;
302+ }
186303}
187304
188305// export function contextMenu(uri: vscode.Uri): Promise<void> {
@@ -197,3 +314,20 @@ export async function mainMenu(uri: vscode.Uri) {
197314 const studioActions = new StudioActions ( uri ) ;
198315 return studioActions && studioActions . getMenu ( "" ) ;
199316}
317+
318+ export async function fireAttemptedEdit ( uri : vscode . Uri ) {
319+ if ( ! uri || uri . scheme !== FILESYSTEM_SCHEMA ) {
320+ return ;
321+ }
322+ const studioActions = new StudioActions ( uri ) ;
323+ studioActions . attemptedEdit ( ) ;
324+ }
325+
326+ export async function contextMenu ( node : PackageNode | ClassNode | RoutineNode ) : Promise < any > {
327+ const nodeOrUri = node || vscode . window . activeTextEditor . document . uri ;
328+ if ( ! nodeOrUri || ( nodeOrUri instanceof vscode . Uri && nodeOrUri . scheme !== FILESYSTEM_SCHEMA ) ) {
329+ return ;
330+ }
331+ const studioActions = new StudioActions ( nodeOrUri ) ;
332+ return studioActions && studioActions . getMenu ( "" , true ) ;
333+ }
0 commit comments