@@ -194,7 +194,104 @@ async function requestServer(
194
194
ServerConnection . makeRequest ( url , init , settings )
195
195
. then ( async response => {
196
196
if ( ! response . ok ) {
197
- promise . reject ( await ServerConnection . ResponseError . create ( response ) ) ;
197
+ if ( response . status === 300 ) {
198
+ let replyUrl = response . headers . get ( 'Location' ) || '' ;
199
+
200
+ if ( ! replyUrl . startsWith ( settings . baseUrl ) ) {
201
+ replyUrl = URLExt . join ( settings . baseUrl , replyUrl ) ;
202
+ }
203
+ const { parent_header, input_request } = await response . json ( ) ;
204
+ // TODO only the client sending the snippet will be prompted for the input
205
+ // we can have a deadlock if its connection is lost.
206
+ const panel = new Panel ( ) ;
207
+ panel . addClass ( 'jp-OutputArea-child' ) ;
208
+ panel . addClass ( 'jp-OutputArea-stdin-item' ) ;
209
+
210
+ const prompt = new OutputPrompt ( ) ;
211
+ prompt . addClass ( 'jp-OutputArea-prompt' ) ;
212
+ panel . addWidget ( prompt ) ;
213
+
214
+ const input = new Stdin ( {
215
+ future : Object . freeze ( {
216
+ sendInputReply : (
217
+ content : KernelMessage . IInputReply ,
218
+ parent_header : KernelMessage . IHeader < 'input_request' >
219
+ ) => {
220
+ ServerConnection . makeRequest (
221
+ replyUrl ,
222
+ {
223
+ method : 'POST' ,
224
+ body : JSON . stringify ( { input : content . value } )
225
+ } ,
226
+ settings
227
+ ) . catch ( error => {
228
+ console . error (
229
+ `Failed to set input to ${ JSON . stringify ( content ) } .` ,
230
+ error
231
+ ) ;
232
+ } ) ;
233
+ }
234
+ } ) as any ,
235
+ parent_header,
236
+ password : input_request . password ,
237
+ prompt : input_request . prompt ,
238
+ translator
239
+ } ) ;
240
+ input . addClass ( 'jp-OutputArea-output' ) ;
241
+ panel . addWidget ( input ) ;
242
+
243
+ // Get the input node to ensure focus after updating the model upon user reply.
244
+ const inputNode = input . node . getElementsByTagName ( 'input' ) [ 0 ] ;
245
+
246
+ void input . value . then ( value => {
247
+ panel . addClass ( 'jp-OutputArea-stdin-hiding' ) ;
248
+
249
+ // FIXME this is not great as the model should not be modified on the client.
250
+ // Use stdin as the stream so it does not get combined with stdout.
251
+ // Note: because it modifies DOM it may (will) shift focus away from the input node.
252
+ cell . outputArea . model . add ( {
253
+ output_type : 'stream' ,
254
+ name : 'stdin' ,
255
+ text : value + '\n'
256
+ } ) ;
257
+ // Refocus the input node after it lost focus due to update of the model.
258
+ inputNode . focus ( ) ;
259
+
260
+ // Keep the input in view for a little while; this (along refocusing)
261
+ // ensures that we can avoid the cell editor stealing the focus, and
262
+ // leading to user inadvertently modifying editor content when executing
263
+ // consecutive commands in short succession.
264
+ window . setTimeout ( async ( ) => {
265
+ // Tack currently focused element to ensure that it remains on it
266
+ // after disposal of the panel with the old input
267
+ // (which modifies DOM and can lead to focus jump).
268
+ const focusedElement = document . activeElement ;
269
+ // Dispose the old panel with no longer needed input box.
270
+ panel . dispose ( ) ;
271
+ // Refocus the element that was focused before.
272
+ if ( focusedElement && focusedElement instanceof HTMLElement ) {
273
+ focusedElement . focus ( ) ;
274
+ }
275
+
276
+ try {
277
+ const response = await requestServer (
278
+ cell ,
279
+ url ,
280
+ init ,
281
+ settings ,
282
+ translator
283
+ ) ;
284
+ promise . resolve ( response ) ;
285
+ } catch ( error ) {
286
+ promise . reject ( error ) ;
287
+ }
288
+ } , 500 ) ;
289
+ } ) ;
290
+
291
+ cell . outputArea . layout . addWidget ( panel ) ;
292
+ } else {
293
+ promise . reject ( await ServerConnection . ResponseError . create ( response ) ) ;
294
+ }
198
295
} else if ( response . status === 202 ) {
199
296
let redirectUrl = response . headers . get ( 'Location' ) || url ;
200
297
@@ -234,98 +331,6 @@ async function requestServer(
234
331
// Evanescent interval
235
332
Math . min ( MAX_POLLING_INTERVAL , interval * 2 )
236
333
) ;
237
- } else if ( response . status === 300 ) {
238
- let replyUrl = response . headers . get ( 'Location' ) || '' ;
239
-
240
- if ( ! replyUrl . startsWith ( settings . baseUrl ) ) {
241
- replyUrl = URLExt . join ( settings . baseUrl , replyUrl ) ;
242
- }
243
- const { parent_header, input_request } = await response . json ( ) ;
244
- // TODO only the client sending the snippet will be prompted for the input
245
- // we can have a deadlock if its connection is lost.
246
- const panel = new Panel ( ) ;
247
- panel . addClass ( 'jp-OutputArea-child' ) ;
248
- panel . addClass ( 'jp-OutputArea-stdin-item' ) ;
249
-
250
- const prompt = new OutputPrompt ( ) ;
251
- prompt . addClass ( 'jp-OutputArea-prompt' ) ;
252
- panel . addWidget ( prompt ) ;
253
-
254
- const input = new Stdin ( {
255
- future : Object . freeze ( {
256
- sendInputReply : (
257
- content : KernelMessage . IInputReply ,
258
- parent_header : KernelMessage . IHeader < 'input_request' >
259
- ) => {
260
- ServerConnection . makeRequest (
261
- replyUrl ,
262
- { method : 'POST' } ,
263
- settings
264
- ) . catch ( error => {
265
- console . error (
266
- `Failed to set input to ${ JSON . stringify ( content ) } .` ,
267
- error
268
- ) ;
269
- } ) ;
270
- }
271
- } ) as any ,
272
- parent_header,
273
- password : input_request . password ,
274
- prompt : input_request . prompt ,
275
- translator
276
- } ) ;
277
- input . addClass ( 'jp-OutputArea-output' ) ;
278
- panel . addWidget ( input ) ;
279
-
280
- // Get the input node to ensure focus after updating the model upon user reply.
281
- const inputNode = input . node . getElementsByTagName ( 'input' ) [ 0 ] ;
282
-
283
- void input . value . then ( value => {
284
- panel . addClass ( 'jp-OutputArea-stdin-hiding' ) ;
285
-
286
- // FIXME this is not great as the model should not be modified on the client.
287
- // Use stdin as the stream so it does not get combined with stdout.
288
- // Note: because it modifies DOM it may (will) shift focus away from the input node.
289
- cell . outputArea . model . add ( {
290
- output_type : 'stream' ,
291
- name : 'stdin' ,
292
- text : value + '\n'
293
- } ) ;
294
- // Refocus the input node after it lost focus due to update of the model.
295
- inputNode . focus ( ) ;
296
-
297
- // Keep the input in view for a little while; this (along refocusing)
298
- // ensures that we can avoid the cell editor stealing the focus, and
299
- // leading to user inadvertently modifying editor content when executing
300
- // consecutive commands in short succession.
301
- window . setTimeout ( async ( ) => {
302
- // Tack currently focused element to ensure that it remains on it
303
- // after disposal of the panel with the old input
304
- // (which modifies DOM and can lead to focus jump).
305
- const focusedElement = document . activeElement ;
306
- // Dispose the old panel with no longer needed input box.
307
- panel . dispose ( ) ;
308
- // Refocus the element that was focused before.
309
- if ( focusedElement && focusedElement instanceof HTMLElement ) {
310
- focusedElement . focus ( ) ;
311
- }
312
-
313
- try {
314
- const response = await requestServer (
315
- cell ,
316
- url ,
317
- init ,
318
- settings ,
319
- translator
320
- ) ;
321
- promise . resolve ( response ) ;
322
- } catch ( error ) {
323
- promise . reject ( error ) ;
324
- }
325
- } , 500 ) ;
326
- } ) ;
327
-
328
- cell . outputArea . layout . addWidget ( panel ) ;
329
334
} else {
330
335
promise . resolve ( response ) ;
331
336
}
0 commit comments