22// Distributed under the terms of the Modified BSD License.
33
44import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
5- import * as nbformat from '@jupyterlab/nbformat' ;
65
76import { DocumentRegistry } from '@jupyterlab/docregistry' ;
87
8+ import * as nbformat from '@jupyterlab/nbformat' ;
9+
10+ import {
11+ IConsoleTracker ,
12+ CodeConsole ,
13+ ConsolePanel ,
14+ } from '@jupyterlab/console' ;
15+
916import {
1017 INotebookModel ,
1118 INotebookTracker ,
@@ -30,11 +37,13 @@ import { filter } from '@lumino/algorithm';
3037
3138import { DisposableDelegate } from '@lumino/disposable' ;
3239
33- import { AttachedProperty } from '@lumino/properties' ;
34-
3540import { WidgetRenderer } from './renderer' ;
3641
37- import { WidgetManager , WIDGET_VIEW_MIMETYPE } from './manager' ;
42+ import {
43+ WidgetManager ,
44+ WIDGET_VIEW_MIMETYPE ,
45+ KernelWidgetManager ,
46+ } from './manager' ;
3847
3948import { OutputModel , OutputView , OUTPUT_WIDGET_VERSION } from './output' ;
4049
@@ -48,6 +57,7 @@ import '@jupyter-widgets/base/css/index.css';
4857import '@jupyter-widgets/controls/css/widgets-base.css' ;
4958import { KernelMessage } from '@jupyterlab/services' ;
5059import { ITranslator , nullTranslator } from '@jupyterlab/translation' ;
60+ import { ISessionContext } from '@jupyterlab/apputils' ;
5161
5262const WIDGET_REGISTRY : base . IWidgetRegistryData [ ] = [ ] ;
5363
@@ -59,7 +69,7 @@ const SETTINGS: WidgetManager.Settings = { saveState: false };
5969/**
6070 * Iterate through all widget renderers in a notebook.
6171 */
62- function * widgetRenderers (
72+ function * notebookWidgetRenderers (
6373 nb : Notebook
6474) : Generator < WidgetRenderer , void , unknown > {
6575 for ( const cell of nb . widgets ) {
@@ -77,6 +87,25 @@ function* widgetRenderers(
7787 }
7888}
7989
90+ /**
91+ * Iterate through all widget renderers in a console.
92+ */
93+ function * consoleWidgetRenderers (
94+ console : CodeConsole
95+ ) : Generator < WidgetRenderer , void , unknown > {
96+ for ( const cell of Array . from ( console . cells ) ) {
97+ if ( cell . model . type === 'code' ) {
98+ for ( const codecell of ( cell as unknown as CodeCell ) . outputArea . widgets ) {
99+ for ( const output of Array . from ( codecell . children ( ) ) ) {
100+ if ( output instanceof WidgetRenderer ) {
101+ yield output ;
102+ }
103+ }
104+ }
105+ }
106+ }
107+ }
108+
80109/**
81110 * Iterate through all matching linked output views
82111 */
@@ -109,16 +138,69 @@ function* chain<T>(
109138 }
110139}
111140
112- export function registerWidgetManager (
113- context : DocumentRegistry . IContext < INotebookModel > ,
141+ /**
142+ * Get the kernel id of current notebook or console panel, this value
143+ * is used as key for `Private.widgetManagerProperty` to store the widget
144+ * manager of current notebook or console panel.
145+ *
146+ * @param {ISessionContext } sessionContext The session context of notebook or
147+ * console panel.
148+ */
149+ async function getWidgetManagerOwner (
150+ sessionContext : ISessionContext
151+ ) : Promise < Private . IWidgetManagerOwner > {
152+ await sessionContext . ready ;
153+ return sessionContext . session ! . kernel ! . id ;
154+ }
155+
156+ /**
157+ * Common handler for registering both notebook and console
158+ * `WidgetManager`
159+ *
160+ * @param {(Notebook | CodeConsole) } content Context of panel.
161+ * @param {ISessionContext } sessionContext Session context of panel.
162+ * @param {IRenderMimeRegistry } rendermime Rendermime of panel.
163+ * @param {IterableIterator<WidgetRenderer> } renderers Iterator of
164+ * `WidgetRenderer` inside panel
165+ * @param {(() => WidgetManager | KernelWidgetManager) } widgetManagerFactory
166+ * function to create widget manager.
167+ */
168+ async function registerWidgetHandler (
169+ content : Notebook | CodeConsole ,
170+ sessionContext : ISessionContext ,
114171 rendermime : IRenderMimeRegistry ,
115- renderers : IterableIterator < WidgetRenderer >
116- ) : DisposableDelegate {
117- let wManager = Private . widgetManagerProperty . get ( context ) ;
172+ renderers : IterableIterator < WidgetRenderer > ,
173+ widgetManagerFactory : ( ) => WidgetManager | KernelWidgetManager
174+ ) : Promise < DisposableDelegate > {
175+ const wManagerOwner = await getWidgetManagerOwner ( sessionContext ) ;
176+ let wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
177+ let currentOwner : string ;
178+
118179 if ( ! wManager ) {
119- wManager = new WidgetManager ( context , rendermime , SETTINGS ) ;
180+ wManager = widgetManagerFactory ( ) ;
120181 WIDGET_REGISTRY . forEach ( ( data ) => wManager ! . register ( data ) ) ;
121- Private . widgetManagerProperty . set ( context , wManager ) ;
182+ Private . widgetManagerProperty . set ( wManagerOwner , wManager ) ;
183+ currentOwner = wManagerOwner ;
184+ content . disposed . connect ( ( _ ) => {
185+ const currentwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
186+ if ( currentwManager ) {
187+ Private . widgetManagerProperty . delete ( currentOwner ) ;
188+ }
189+ } ) ;
190+
191+ sessionContext . kernelChanged . connect ( ( _ , args ) => {
192+ const { newValue } = args ;
193+ if ( newValue ) {
194+ const newKernelId = newValue . id ;
195+ const oldwManager = Private . widgetManagerProperty . get ( currentOwner ) ;
196+
197+ if ( oldwManager ) {
198+ Private . widgetManagerProperty . delete ( currentOwner ) ;
199+ Private . widgetManagerProperty . set ( newKernelId , oldwManager ) ;
200+ }
201+ currentOwner = newKernelId ;
202+ }
203+ } ) ;
122204 }
123205
124206 for ( const r of renderers ) {
@@ -145,6 +227,92 @@ export function registerWidgetManager(
145227 } ) ;
146228}
147229
230+ // Kept for backward compat ipywidgets<=8, but not used here anymore
231+ export function registerWidgetManager (
232+ context : DocumentRegistry . IContext < INotebookModel > ,
233+ rendermime : IRenderMimeRegistry ,
234+ renderers : IterableIterator < WidgetRenderer >
235+ ) : DisposableDelegate {
236+ let wManager : WidgetManager ;
237+ const managerReady = getWidgetManagerOwner ( context . sessionContext ) . then (
238+ ( wManagerOwner ) => {
239+ const currentManager = Private . widgetManagerProperty . get (
240+ wManagerOwner
241+ ) as WidgetManager ;
242+ if ( ! currentManager ) {
243+ wManager = new WidgetManager ( context , rendermime , SETTINGS ) ;
244+ WIDGET_REGISTRY . forEach ( ( data ) => wManager ! . register ( data ) ) ;
245+ Private . widgetManagerProperty . set ( wManagerOwner , wManager ) ;
246+ } else {
247+ wManager = currentManager ;
248+ }
249+
250+ for ( const r of renderers ) {
251+ r . manager = wManager ;
252+ }
253+
254+ // Replace the placeholder widget renderer with one bound to this widget
255+ // manager.
256+ rendermime . removeMimeType ( WIDGET_VIEW_MIMETYPE ) ;
257+ rendermime . addFactory (
258+ {
259+ safe : false ,
260+ mimeTypes : [ WIDGET_VIEW_MIMETYPE ] ,
261+ createRenderer : ( options ) => new WidgetRenderer ( options , wManager ) ,
262+ } ,
263+ - 10
264+ ) ;
265+ }
266+ ) ;
267+
268+ return new DisposableDelegate ( async ( ) => {
269+ await managerReady ;
270+ if ( rendermime ) {
271+ rendermime . removeMimeType ( WIDGET_VIEW_MIMETYPE ) ;
272+ }
273+ wManager ! . dispose ( ) ;
274+ } ) ;
275+ }
276+
277+ export async function registerNotebookWidgetManager (
278+ panel : NotebookPanel ,
279+ renderers : IterableIterator < WidgetRenderer >
280+ ) : Promise < DisposableDelegate > {
281+ const content = panel . content ;
282+ const context = panel . context ;
283+ const sessionContext = context . sessionContext ;
284+ const rendermime = content . rendermime ;
285+ const widgetManagerFactory = ( ) =>
286+ new WidgetManager ( context , rendermime , SETTINGS ) ;
287+
288+ return registerWidgetHandler (
289+ content ,
290+ sessionContext ,
291+ rendermime ,
292+ renderers ,
293+ widgetManagerFactory
294+ ) ;
295+ }
296+
297+ export async function registerConsoleWidgetManager (
298+ panel : ConsolePanel ,
299+ renderers : IterableIterator < WidgetRenderer >
300+ ) : Promise < DisposableDelegate > {
301+ const content = panel . console ;
302+ const sessionContext = content . sessionContext ;
303+ const rendermime = content . rendermime ;
304+ const widgetManagerFactory = ( ) =>
305+ new KernelWidgetManager ( sessionContext . session ! . kernel ! , rendermime ) ;
306+
307+ return registerWidgetHandler (
308+ content ,
309+ sessionContext ,
310+ rendermime ,
311+ renderers ,
312+ widgetManagerFactory
313+ ) ;
314+ }
315+
148316/**
149317 * The widget manager provider.
150318 */
@@ -154,6 +322,7 @@ export const managerPlugin: JupyterFrontEndPlugin<base.IJupyterWidgetRegistry> =
154322 requires : [ IRenderMimeRegistry ] ,
155323 optional : [
156324 INotebookTracker ,
325+ IConsoleTracker ,
157326 ISettingRegistry ,
158327 IMainMenu ,
159328 ILoggerRegistry ,
@@ -175,6 +344,7 @@ function activateWidgetExtension(
175344 app : JupyterFrontEnd ,
176345 rendermime : IRenderMimeRegistry ,
177346 tracker : INotebookTracker | null ,
347+ consoleTracker : IConsoleTracker | null ,
178348 settingRegistry : ISettingRegistry | null ,
179349 menu : IMainMenu | null ,
180350 loggerRegistry : ILoggerRegistry | null ,
@@ -183,15 +353,23 @@ function activateWidgetExtension(
183353 const { commands } = app ;
184354 const trans = ( translator ?? nullTranslator ) . load ( 'jupyterlab_widgets' ) ;
185355
186- const bindUnhandledIOPubMessageSignal = ( nb : NotebookPanel ) : void => {
356+ const bindUnhandledIOPubMessageSignal = async (
357+ nb : NotebookPanel
358+ ) : Promise < void > => {
187359 if ( ! loggerRegistry ) {
188360 return ;
189361 }
362+ const wManagerOwner = await getWidgetManagerOwner (
363+ nb . context . sessionContext
364+ ) ;
365+ const wManager = Private . widgetManagerProperty . get ( wManagerOwner ) ;
190366
191- const wManager = Private . widgetManagerProperty . get ( nb . context ) ;
192367 if ( wManager ) {
193368 wManager . onUnhandledIOPubMessage . connect (
194- ( sender : WidgetManager , msg : KernelMessage . IIOPubMessage ) => {
369+ (
370+ sender : WidgetManager | KernelWidgetManager ,
371+ msg : KernelMessage . IIOPubMessage
372+ ) => {
195373 const logger = loggerRegistry . getLogger ( nb . context . path ) ;
196374 let level : LogLevel = 'warning' ;
197375 if (
@@ -233,32 +411,32 @@ function activateWidgetExtension(
233411 ) ;
234412
235413 if ( tracker !== null ) {
236- tracker . forEach ( ( panel ) => {
237- registerWidgetManager (
238- panel . context ,
239- panel . content . rendermime ,
240- chain (
241- widgetRenderers ( panel . content ) ,
242- outputViews ( app , panel . context . path )
243- )
414+ const rendererIterator = ( panel : NotebookPanel ) =>
415+ chain (
416+ notebookWidgetRenderers ( panel . content ) ,
417+ outputViews ( app , panel . context . path )
244418 ) ;
245-
419+ tracker . forEach ( async ( panel ) => {
420+ await registerNotebookWidgetManager ( panel , rendererIterator ( panel ) ) ;
246421 bindUnhandledIOPubMessageSignal ( panel ) ;
247422 } ) ;
248- tracker . widgetAdded . connect ( ( sender , panel ) => {
249- registerWidgetManager (
250- panel . context ,
251- panel . content . rendermime ,
252- chain (
253- widgetRenderers ( panel . content ) ,
254- outputViews ( app , panel . context . path )
255- )
256- ) ;
257-
423+ tracker . widgetAdded . connect ( async ( sender , panel ) => {
424+ await registerNotebookWidgetManager ( panel , rendererIterator ( panel ) ) ;
258425 bindUnhandledIOPubMessageSignal ( panel ) ;
259426 } ) ;
260427 }
261428
429+ if ( consoleTracker !== null ) {
430+ const rendererIterator = ( panel : ConsolePanel ) =>
431+ chain ( consoleWidgetRenderers ( panel . console ) ) ;
432+
433+ consoleTracker . forEach ( async ( panel ) => {
434+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
435+ } ) ;
436+ consoleTracker . widgetAdded . connect ( async ( sender , panel ) => {
437+ await registerConsoleWidgetManager ( panel , rendererIterator ( panel ) ) ;
438+ } ) ;
439+ }
262440 if ( settingRegistry !== null ) {
263441 // Add a command for automatically saving (jupyter-)widget state.
264442 commands . addCommand ( '@jupyter-widgets/jupyterlab-manager:saveWidgetState' , {
@@ -378,13 +556,23 @@ export default [
378556] ;
379557namespace Private {
380558 /**
381- * A private attached property for a widget manager .
559+ * A type alias for keys of `widgetManagerProperty` .
382560 */
383- export const widgetManagerProperty = new AttachedProperty <
384- DocumentRegistry . Context ,
385- WidgetManager | undefined
386- > ( {
387- name : 'widgetManager' ,
388- create : ( owner : DocumentRegistry . Context ) : undefined => undefined ,
389- } ) ;
561+ export type IWidgetManagerOwner = string ;
562+
563+ /**
564+ * A type alias for values of `widgetManagerProperty` .
565+ */
566+ export type IWidgetManagerValue =
567+ | WidgetManager
568+ | KernelWidgetManager
569+ | undefined ;
570+
571+ /**
572+ * A private map for a widget manager.
573+ */
574+ export const widgetManagerProperty = new Map <
575+ IWidgetManagerOwner ,
576+ IWidgetManagerValue
577+ > ( ) ;
390578}
0 commit comments