4
4
import { JupyterFrontEnd } from '@jupyterlab/application' ;
5
5
import { PageConfig } from '@jupyterlab/coreutils' ;
6
6
import { DocumentRegistry } from '@jupyterlab/docregistry' ;
7
+ import { IRankedMenu } from '@jupyterlab/ui-components' ;
7
8
8
9
import { ArrayExt , find , IIterator , iter } from '@lumino/algorithm' ;
10
+ import { CommandRegistry } from '@lumino/commands' ;
9
11
import { PromiseDelegate , Token } from '@lumino/coreutils' ;
12
+ import { IDisposable } from '@lumino/disposable' ;
10
13
import { Message , MessageLoop , IMessageHandler } from '@lumino/messaging' ;
11
14
import { Debouncer } from '@lumino/polling' ;
12
15
import { ISignal , Signal } from '@lumino/signaling' ;
13
16
14
17
import {
15
18
BoxLayout ,
16
19
Layout ,
20
+ Menu ,
17
21
Panel ,
18
22
SplitPanel ,
19
23
StackedPanel ,
@@ -47,8 +51,8 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
47
51
48
52
this . _topHandler = new Private . PanelHandler ( ) ;
49
53
this . _menuHandler = new Private . PanelHandler ( ) ;
50
- this . _leftHandler = new Private . SideBarHandler ( ) ;
51
- this . _rightHandler = new Private . SideBarHandler ( ) ;
54
+ this . _leftHandler = new Private . SideBarHandler ( 'left' ) ;
55
+ this . _rightHandler = new Private . SideBarHandler ( 'right' ) ;
52
56
this . _main = new Panel ( ) ;
53
57
const topWrapper = ( this . _topWrapper = new Panel ( ) ) ;
54
58
const menuWrapper = ( this . _menuWrapper = new Panel ( ) ) ;
@@ -526,12 +530,14 @@ namespace Private {
526
530
/**
527
531
* Construct a new side bar handler.
528
532
*/
529
- constructor ( ) {
533
+ constructor ( area : 'left' | 'right' ) {
534
+ this . _area = area ;
530
535
this . _stackedPanel = new StackedPanel ( ) ;
531
536
this . _stackedPanel . hide ( ) ;
532
537
this . _current = null ;
533
538
this . _lastCurrent = null ;
534
539
this . _stackedPanel . widgetRemoved . connect ( this . _onWidgetRemoved , this ) ;
540
+ this . _sideBarMenu = null ;
535
541
}
536
542
537
543
get current ( ) : Widget | null {
@@ -563,6 +569,13 @@ namespace Private {
563
569
return this . _updated ;
564
570
}
565
571
572
+ /**
573
+ * Associate a menu entry to the sidebar.
574
+ */
575
+ createMenuEntry ( options : SideBarMenuOption ) : void {
576
+ this . _sideBarMenu = new SideBarMenu ( options ) ;
577
+ }
578
+
566
579
/**
567
580
* Expand the sidebar.
568
581
*
@@ -619,8 +632,7 @@ namespace Private {
619
632
ArrayExt . insert ( this . _items , index , item ) ;
620
633
this . _stackedPanel . insertWidget ( index , widget ) ;
621
634
622
- // TODO: Update menu to include widget in appropriate position
623
-
635
+ this . updateMenu ( ) ;
624
636
this . _refreshVisibility ( ) ;
625
637
}
626
638
@@ -640,6 +652,14 @@ namespace Private {
640
652
this . _refreshVisibility ( ) ;
641
653
}
642
654
655
+ /**
656
+ * Update menu entries
657
+ */
658
+ updateMenu ( ) : void {
659
+ if ( ! this . _sideBarMenu ) return ;
660
+ const widgets = this . stackedPanel . widgets ;
661
+ this . _sideBarMenu ?. updateMenu ( widgets , this . _area ) ;
662
+ }
643
663
/**
644
664
* Find the insertion index for a rank item.
645
665
*/
@@ -678,15 +698,100 @@ namespace Private {
678
698
this . _lastCurrent = null ;
679
699
}
680
700
ArrayExt . removeAt ( this . _items , this . _findWidgetIndex ( widget ) ) ;
681
- // TODO: Remove the widget from the menu
701
+
702
+ this . updateMenu ( ) ;
682
703
this . _refreshVisibility ( ) ;
683
704
}
684
705
706
+ private _area : 'left' | 'right' ;
685
707
private _isHiddenByUser = false ;
686
708
private _items = new Array < Private . IRankItem > ( ) ;
687
709
private _stackedPanel : StackedPanel ;
688
710
private _current : Widget | null ;
689
711
private _lastCurrent : Widget | null ;
690
712
private _updated : Signal < SideBarHandler , void > = new Signal ( this ) ;
713
+ private _sideBarMenu : SideBarMenu | null ;
714
+ }
715
+
716
+ /**
717
+ * A class which manages the menu entry associated to the side bar.
718
+ */
719
+ export class SideBarMenu {
720
+ /**
721
+ * Construct a new side bar handler.
722
+ */
723
+ constructor ( options : SideBarMenuOption ) {
724
+ this . _commandRegistry = options . commandRegistry ;
725
+ this . _command = options . command ;
726
+ this . _mainMenuEntry = options . mainMenuEntry ;
727
+ this . _entryLabel = options . entryLabel ;
728
+ }
729
+
730
+ /**
731
+ * Update the menu by disposing the previous one and rebuilding a new one from widgets list.
732
+ */
733
+ updateMenu ( widgets : Readonly < Widget [ ] > , area : 'left' | 'right' ) : void {
734
+ // Remove the previous menu entry.
735
+ if ( this . _menu ) this . _menu . dispose ( ) ;
736
+
737
+ // Build the new menu entry from widgets list.
738
+ let menu = new Menu ( { commands : this . _commandRegistry } ) ;
739
+ menu . title . label = this . _entryLabel ;
740
+ widgets . forEach ( widget => {
741
+ menu . addItem ( {
742
+ command : this . _command ,
743
+ args : {
744
+ side : area ,
745
+ title : widget . title . caption ,
746
+ id : widget . id
747
+ }
748
+ } ) ;
749
+ } ) ;
750
+
751
+ // If there are widgets, add the menu to the main menu entry.
752
+ if ( widgets . length > 0 ) {
753
+ this . _menu = this . _mainMenuEntry . addItem ( {
754
+ type : 'submenu' ,
755
+ submenu : menu
756
+ } ) ;
757
+ }
758
+ }
759
+
760
+ _entryLabel : string ;
761
+ _command : string ;
762
+ _mainMenuEntry : IRankedMenu ;
763
+ _commandRegistry : CommandRegistry ;
764
+ _menu : IDisposable | null = null ;
691
765
}
766
+
767
+ /**
768
+ * An interface for the options to include in SideBarMenu constructor.
769
+ */
770
+ type SideBarMenuOption = {
771
+ /**
772
+ * The main menu entry where the sidebar menu should be added.
773
+ */
774
+ mainMenuEntry : IRankedMenu ;
775
+
776
+ /**
777
+ * Tha label of the sidebar menu.
778
+ */
779
+ entryLabel : string ;
780
+
781
+ /**
782
+ * The application command registry, necessary when updating the sidebar menu.
783
+ */
784
+ commandRegistry : CommandRegistry ;
785
+
786
+ /**
787
+ * The command to call from each sidebar menu entry.
788
+ *
789
+ * ### Notes
790
+ * That command required 3 args :
791
+ * side: 'left' | 'right', the area to toggle
792
+ * title: string, label of the command
793
+ * id: string, id of the widget to activate
794
+ */
795
+ command : string ;
796
+ } ;
692
797
}
0 commit comments