1- import { getTypePickerView } from "./typePicker " ;
2- import { block , autoSizeInput } from "../../domUtils " ;
1+ import { block , autoSizeInput , awaitInlineInput } from "../../domUtils " ;
2+ import { addChange } from "../changes " ;
33
44/**
55 * Replaces the strings with spaces
@@ -16,7 +16,7 @@ function padSpace (string) {
1616/**
1717 * A hero function that handles formalSpec string like 'test2:%String(VALUELIST="1,2,3",MAXLEN=1)={"test"+"best"+{"a":1}},noType,typeOnly:Cinema.TicketOrder={##class(TestPack.MyType).%New("AHA!, AHAHA, AA!",1)},defaultOnly="lol"'
1818 * @param {string } formalSpec =
19- * @returns {string [] }
19+ * @returns {* [] }
2020 */
2121function splitArguments ( formalSpec = "" ) {
2222
@@ -90,33 +90,246 @@ function hide (element) {
9090 element . style . display = "none" ;
9191}
9292
93- export function getFormalSpecEditor ( { formalSpec = "" , savePath } ) {
93+ function getParameterView ( model , save , del , blur ) {
94+
95+ let span = block ( `span` , `parameter` ) ,
96+ eq = block ( `span` , `secondary` , ` = ` ) ,
97+ nameInput = autoSizeInput ( {
98+ placeholder : `Name` ,
99+ value : model . name || ""
100+ } ) ,
101+ valueInput = autoSizeInput ( {
102+ placeholder : `Value` ,
103+ value : model . value || ""
104+ } ) ;
105+
106+ span . appendChild ( nameInput ) ;
107+ span . appendChild ( eq ) ;
108+ span . appendChild ( valueInput ) ;
109+
110+ nameInput . addEventListener ( `input` , ( ) => {
111+ model . name = nameInput . value ;
112+ save ( ) ;
113+ } ) ;
114+ valueInput . addEventListener ( `input` , ( ) => {
115+ model . value = valueInput . value ;
116+ save ( ) ;
117+ } ) ;
118+ nameInput . addEventListener ( `blur` , ( ) => {
119+ if ( nameInput . value !== "" )
120+ return ;
121+ if ( span . parentNode )
122+ span . parentNode . removeChild ( span ) ;
123+ del ( model ) ;
124+ } ) ;
125+ nameInput . addEventListener ( `blur` , blur ) ;
126+ valueInput . addEventListener ( `blur` , blur ) ;
127+
128+ return span ;
129+
130+ }
94131
95- let container = block ( `div` , `formalSpecEdit` ) ,
96- args = splitArguments ( formalSpec ) ;
97-
98- args . forEach ( ( arg , i ) => {
99-
100- let span = block ( `span` , `argument` ) ,
101- name = autoSizeInput ( { placeholder : `Name` , value : arg . name , className : `nameInput` } ) ,
102- asSpan = block ( `span` , `typeSpan` ) ,
103- defaultSpan = block ( `span` ) ;
104-
105- if ( i > 0 )
106- span . appendChild ( block ( `span` , `` , `, ` ) ) ;
107-
108- span . appendChild ( name ) ;
109- asSpan . appendChild ( block ( `span` , `` , ` As ` ) ) ;
110- let typeInput = autoSizeInput ( { placeholder : `Type` , value : arg . type || "" } ) ;
111- if ( ! arg . type ) {
112- hide ( asSpan ) ;
132+ function getParamsSpan ( parameters = [ ] , save , blur ) {
133+
134+ let paramsSpan = block ( `span` , `parametersSpan` ) ,
135+ paramPlus = block ( `span` , `parameter` ) ,
136+ plusEl = block ( `span` , `interactive small add icon` ) ;
137+
138+ function del ( model ) {
139+ for ( let i = 0 ; i < parameters . length ; i ++ ) {
140+ if ( parameters [ i ] === model ) {
141+ parameters . splice ( i , 1 ) ;
142+ break ;
143+ }
113144 }
114- asSpan . appendChild ( typeInput ) ;
115- span . appendChild ( asSpan ) ;
116- span . appendChild ( defaultSpan ) ;
117-
118- container . appendChild ( span ) ;
145+ save ( ) ;
146+ }
147+
148+ for ( let p of parameters ) {
149+ paramsSpan . appendChild ( getParameterView ( p , save , del , blur ) ) ;
150+ }
151+
152+ paramPlus . appendChild ( plusEl ) ;
153+ paramsSpan . appendChild ( paramPlus ) ;
154+ plusEl . addEventListener ( `click` , ( ) => awaitInlineInput ( plusEl , {
155+ placeholder : `New Parameter...`
156+ } , ( cancelled , name ) => {
157+
158+ if ( cancelled )
159+ return ;
160+
161+ let model = {
162+ name : name ,
163+ value : ""
164+ } ;
165+
166+ paramsSpan . insertBefore ( getParameterView ( model , save , del , blur ) , paramPlus ) ;
167+ parameters . push ( model ) ;
168+
169+ } ) ) ;
170+
171+ return paramsSpan ;
172+
173+ }
174+
175+ /**
176+ * @param {* } model
177+ * @param {function } save - Function that saves the model.
178+ * @param {function } remove - Function that removes the model part and saves the new model as well.
179+ * @returns {Element }
180+ */
181+ function getArgumentView ( model , save , remove ) {
182+
183+ let argumentSpan = block ( `span` , `argument` ) ,
184+ nameInput = autoSizeInput ( { placeholder : `Name` , value : model . name , className : `nameInput` } ) ,
185+ asSpan = block ( `span` , `typeSpan` ) ,
186+ defaultSpan = block ( `span` ) ,
187+ paramsSpan = getParamsSpan ( model . parameters , save , blur ) ;
188+
189+ function paramsSpanIsActive ( ) {
190+ return document . activeElement
191+ && ( document . activeElement . parentNode === paramsSpan
192+ || document . activeElement . parentNode . parentNode === paramsSpan ) ;
193+ }
194+
195+ function blur ( ) {
196+ setTimeout ( ( ) => {
197+ if (
198+ document . activeElement !== defaultInput
199+ && document . activeElement !== typeInput
200+ && document . activeElement !== nameInput
201+ && typeInput . value === ""
202+ ) {
203+ hide ( asSpan ) ;
204+ }
205+ if (
206+ document . activeElement !== defaultInput
207+ && document . activeElement !== typeInput
208+ && document . activeElement !== nameInput
209+ && defaultInput . value === ""
210+ ) {
211+ hide ( defaultSpan ) ;
212+ }
213+ if (
214+ document . activeElement !== defaultInput
215+ && document . activeElement !== typeInput
216+ && document . activeElement !== nameInput
217+ && ! paramsSpanIsActive ( )
218+ && ( model . parameters || [ ] ) . length === 0
219+ ) {
220+ hide ( paramsSpan ) ;
221+ }
222+ if ( nameInput . value === "" ) {
223+ if ( argumentSpan . parentNode )
224+ argumentSpan . parentNode . removeChild ( argumentSpan ) ;
225+ remove ( model ) ;
226+ }
227+ } , 200 ) ;
228+ }
229+
230+ argumentSpan . appendChild ( nameInput ) ;
231+
232+ asSpan . appendChild ( block ( `span` , `asSpan` , ` As ` ) ) ;
233+ let typeInput = autoSizeInput ( { placeholder : `Type` , value : model . type || "" } ) ;
234+ if ( ! model . type ) {
235+ hide ( asSpan ) ;
236+ }
237+ asSpan . appendChild ( typeInput ) ;
238+ argumentSpan . appendChild ( asSpan ) ;
239+
240+ if ( ! model . parameters || ! model . parameters . length ) {
241+ hide ( paramsSpan ) ;
242+ }
243+ argumentSpan . appendChild ( paramsSpan ) ;
244+
245+ defaultSpan . appendChild ( block ( `span` , `defSpan` , ` = ` ) ) ;
246+ let defaultInput = autoSizeInput ( { placeholder : `Default` , value : model . default || "" } ) ;
247+ if ( ! model . default ) {
248+ hide ( defaultSpan ) ;
249+ }
250+ defaultSpan . appendChild ( defaultInput ) ;
251+ argumentSpan . appendChild ( defaultSpan ) ;
252+
253+ nameInput . addEventListener ( `focus` , ( ) => {
254+ if ( typeInput . value === "" )
255+ show ( asSpan ) ;
256+ if ( defaultInput . value === "" )
257+ show ( defaultSpan ) ;
258+ } ) ;
259+ nameInput . addEventListener ( `blur` , ( ) => blur ( ) ) ;
260+ typeInput . addEventListener ( `blur` , ( ) => blur ( ) ) ;
261+ defaultInput . addEventListener ( `blur` , ( ) => blur ( ) ) ;
262+ nameInput . addEventListener ( `input` , ( ) => {
263+ if ( ! nameInput . value )
264+ return ;
265+ model . name = nameInput . value ;
266+ save ( ) ;
267+ } ) ;
268+ typeInput . addEventListener ( `input` , ( ) => {
269+ model . type = typeInput . value ;
270+ save ( ) ;
119271 } ) ;
272+ defaultInput . addEventListener ( `input` , ( ) => {
273+ model . default = defaultInput . value ;
274+ save ( ) ;
275+ } ) ;
276+ typeInput . addEventListener ( `focus` , ( ) => {
277+ if ( typeInput . value === "" )
278+ return ;
279+ show ( paramsSpan ) ;
280+ } ) ;
281+
282+ return argumentSpan ;
283+
284+ }
285+
286+ export function getFormalSpecEditor ( { formalSpec = "" , savePath } ) {
287+
288+ let container = block ( `span` , `formalSpecEdit` ) ,
289+ args = splitArguments ( formalSpec ) ,
290+ plusArg = block ( `span` , `argument` ) ,
291+ plusEl = block ( `div` , `interactive small add icon` ) ;
292+
293+ function save ( ) {
294+ let formalSpec = [ ] ;
295+ for ( let fs of args ) {
296+ formalSpec . push ( `${ fs . name } ${ fs . type ? ":" + fs . type : "" } ${
297+ fs . type && fs . parameters && fs . parameters . length
298+ ? "(" + fs . parameters . map ( p => p . name + "=" + p . value ) . join ( "," ) + ")"
299+ : ""
300+ } ${ fs . default ? "=" + fs . default : "" } `) ;
301+ }
302+ addChange ( savePath , formalSpec . join ( `,` ) ) ;
303+ }
304+
305+ function del ( model ) {
306+ for ( let i = 0 ; i < args . length ; i ++ ) {
307+ if ( args [ i ] === model ) {
308+ args . splice ( i , 1 ) ;
309+ break ;
310+ }
311+ }
312+ save ( ) ;
313+ }
314+
315+ args . forEach ( ( arg ) => container . appendChild ( getArgumentView ( arg , save , del ) ) ) ;
316+ plusArg . appendChild ( plusEl ) ;
317+ container . appendChild ( plusArg ) ;
318+ plusEl . addEventListener ( `click` , ( ) => awaitInlineInput ( plusEl , {
319+ placeholder : `New Argument...`
320+ } , ( cancelled , name ) => {
321+
322+ if ( cancelled )
323+ return ;
324+
325+ let model = {
326+ name : name
327+ } ;
328+
329+ container . insertBefore ( getArgumentView ( model , save , del ) , plusArg ) ;
330+ args . push ( model ) ;
331+
332+ } ) ) ;
120333
121334 return container ;
122335
0 commit comments