@@ -47,6 +47,8 @@ import {
4747 SidePanel ,
4848 SidePanelHandler ,
4949 SidePanelPalette ,
50+ INotebookPathOpener ,
51+ defaultNotebookPathOpener ,
5052} from '@jupyter-notebook/application' ;
5153
5254import { jupyterIcon } from '@jupyter-notebook/ui-components' ;
@@ -309,7 +311,7 @@ const pages: JupyterFrontEndPlugin<void> = {
309311 app . commands . addCommand ( CommandIDs . openLab , {
310312 label : trans . __ ( 'Open JupyterLab' ) ,
311313 execute : ( ) => {
312- window . open ( ` ${ baseUrl } lab` ) ;
314+ window . open ( URLExt . join ( baseUrl , ' lab' ) ) ;
313315 } ,
314316 } ) ;
315317 const page = PageConfig . getOption ( 'notebookPage' ) ;
@@ -320,7 +322,7 @@ const pages: JupyterFrontEndPlugin<void> = {
320322 if ( page === 'tree' ) {
321323 app . commands . execute ( 'filebrowser:activate' ) ;
322324 } else {
323- window . open ( ` ${ baseUrl } tree` ) ;
325+ window . open ( URLExt . join ( baseUrl , ' tree' ) ) ;
324326 }
325327 } ,
326328 } ) ;
@@ -332,6 +334,18 @@ const pages: JupyterFrontEndPlugin<void> = {
332334 } ,
333335} ;
334336
337+ /**
338+ * A plugin to open paths in new browser tabs.
339+ */
340+ const pathOpener : JupyterFrontEndPlugin < INotebookPathOpener > = {
341+ id : '@jupyter-notebook/application-extension:path-opener' ,
342+ autoStart : true ,
343+ provides : INotebookPathOpener ,
344+ activate : ( app : JupyterFrontEnd ) : INotebookPathOpener => {
345+ return defaultNotebookPathOpener ;
346+ } ,
347+ } ;
348+
335349/**
336350 * The default paths for a Jupyter Notebook app.
337351 */
@@ -361,16 +375,19 @@ const rendermime: JupyterFrontEndPlugin<IRenderMimeRegistry> = {
361375 ISanitizer ,
362376 IMarkdownParser ,
363377 ITranslator ,
378+ INotebookPathOpener ,
364379 ] ,
365380 activate : (
366381 app : JupyterFrontEnd ,
367382 docManager : IDocumentManager | null ,
368383 latexTypesetter : ILatexTypesetter | null ,
369384 sanitizer : IRenderMime . ISanitizer | null ,
370385 markdownParser : IMarkdownParser | null ,
371- translator : ITranslator | null
386+ translator : ITranslator | null ,
387+ notebookPathOpener : INotebookPathOpener | null
372388 ) => {
373389 const trans = ( translator ?? nullTranslator ) . load ( 'jupyterlab' ) ;
390+ const opener = notebookPathOpener ?? defaultNotebookPathOpener ;
374391 if ( docManager ) {
375392 app . commands . addCommand ( CommandIDs . handleLink , {
376393 label : trans . __ ( 'Handle Local Link' ) ,
@@ -382,10 +399,12 @@ const rendermime: JupyterFrontEndPlugin<IRenderMimeRegistry> = {
382399 return docManager . services . contents
383400 . get ( path , { content : false } )
384401 . then ( ( model ) => {
385- // Open in a new browser tab
386- const url = PageConfig . getBaseUrl ( ) ;
387- const treeUrl = URLExt . join ( url , 'tree' , model . path ) ;
388- window . open ( treeUrl , '_blank' ) ;
402+ const baseUrl = PageConfig . getBaseUrl ( ) ;
403+ opener . open ( {
404+ prefix : URLExt . join ( baseUrl , 'tree' ) ,
405+ path : model . path ,
406+ target : '_blank' ,
407+ } ) ;
389408 } ) ;
390409 } ,
391410 } ) ;
@@ -1089,6 +1108,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
10891108 menuSpacer ,
10901109 opener ,
10911110 pages ,
1111+ pathOpener ,
10921112 paths ,
10931113 rendermime ,
10941114 shell ,
0 commit comments