Browse Source

Migrate application/ to phosphor 1.0

Afshin Darian 8 years ago
parent
commit
a40cbad6a7
3 changed files with 134 additions and 180 deletions
  1. 5 38
      src/application/index.ts
  2. 2 2
      src/application/loader.ts
  3. 127 140
      src/application/shell.ts

+ 5 - 38
src/application/index.ts

@@ -2,11 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  utils
-} from '@jupyterlab/services';
-
-import {
-  Application
+  Application, IPlugin
 } from '@phosphor/application';
 
 import {
@@ -45,7 +41,7 @@ namespace CommandIDs {
  * The type for all JupyterLab plugins.
  */
 export
-type JupyterLabPlugin<T> = Application.IPlugin<JupyterLab, T>;
+type JupyterLabPlugin<T> = IPlugin<JupyterLab, T>;
 
 
 /**
@@ -56,8 +52,8 @@ class JupyterLab extends Application<ApplicationShell> {
   /**
    * Construct a new JupyterLab object.
    */
-  constructor(options: JupyterLab.IOptions = {}) {
-    super();
+  constructor(options: JupyterLab.IOptions = { shell: new ApplicationShell() }) {
+    super(options);
     this._info = {
       gitDescription: options.gitDescription || 'unknown',
       namespace: options.namespace || 'jupyterlab',
@@ -90,26 +86,6 @@ class JupyterLab extends Application<ApplicationShell> {
     return this.shell.restored;
   }
 
-  /**
-   * A promise that resolves when the JupyterLab application is started.
-   */
-  get started(): Promise<void> {
-    return this._startedDelegate.promise;
-  }
-
-  /**
-   * Start the JupyterLab application.
-   */
-  start(options: Application.IStartOptions = {}): Promise<void> {
-    if (this._isStarted) {
-      return Promise.resolve(void 0);
-    }
-    this._isStarted = true;
-    return super.start(options).then(() => {
-      this._startedDelegate.resolve(void 0);
-    });
-  }
-
   /**
    * Register plugins from a plugin module.
    *
@@ -144,17 +120,8 @@ class JupyterLab extends Application<ApplicationShell> {
     window.addEventListener('resize', this);
   }
 
-  /**
-   * Create the application shell for the JupyterLab application.
-   */
-  protected createShell(): ApplicationShell {
-    return new ApplicationShell();
-  }
-
   private _info: JupyterLab.IInfo;
-  private _isStarted = false;
   private _loader: ModuleLoader | null;
-  private _startedDelegate = new utils.PromiseDelegate<void>();
 }
 
 
@@ -167,7 +134,7 @@ namespace JupyterLab {
    * The options used to initialize a JupyterLab object.
    */
   export
-  interface IOptions {
+  interface IOptions extends Application.IOptions<ApplicationShell> {
     /**
      * The git description of the JupyterLab application.
      */

+ 2 - 2
src/application/loader.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  Application
+  Application, IPlugin
 } from '@phosphor/application';
 
 import {
@@ -128,7 +128,7 @@ class ModuleLoader {
    * #### Notes
    * The plugin(s) are extracted and validated before being returned.
    */
-  extractPlugins(data: any): Application.IPlugin<Application<Widget>, any>[] {
+  extractPlugins(data: any): IPlugin<Application<Widget>, any>[] {
     // We use the default export from es6 modules.
     if (data.__esModule) {
       data = data.default;

+ 127 - 140
src/application/shell.ts

@@ -6,19 +6,11 @@ import {
 } from '@jupyterlab/services';
 
 import {
-  each, toArray
+  ArrayExt, each, find, toArray
 } from '@phosphor/algorithm';
 
 import {
-  contains, find, ArrayExt.firstIndexOf, ArrayExt.findFirstIndex, ArrayExt.upperBound
-} from 'phosphor/lib/algorithm/searching';
-
-import {
-  Vector
-} from 'phosphor/lib/collections/vector';
-
-import {
-  defineSignal, ISignal
+  ISignal
 } from '@phosphor/signaling';
 
 import {
@@ -46,15 +38,7 @@ import {
 } from '@phosphor/widgets';
 
 import {
-  TabBar
-} from '@phosphor/widgettabbar';
-
-import {
-  Title
-} from '@phosphor/widgettitle';
-
-import {
-  Widget
+  TabBar, Title, Widget
 } from '@phosphor/widgets';
 
 import {
@@ -146,26 +130,28 @@ class ApplicationShell extends Widget {
 
     this.layout = rootLayout;
 
-    this._dockPanel.currentChanged.connect(this._onCurrentChanged, this);
+    this._tracker.currentChanged.connect(this._onCurrentChanged, this);
   }
 
   /**
    * A signal emitted when main area's current focus changes.
    */
-  readonly currentChanged: ISignal<this, FocusTracker.ICurrentChangedArgs<Widget>>;
+  get currentChanged(): ISignal<any, FocusTracker.IChangedArgs<Widget>> {
+    return this._tracker.currentChanged;
+  }
 
   /**
    * The current widget in the shell's main area.
    */
   get currentWidget(): Widget {
-    return this._dockPanel.currentWidget;
+    return this._tracker.currentWidget;
   }
 
   /**
-   * Promise that resolves when state is restored, returning layout description.
+   * True if left area is empty.
    */
-  get restored(): Promise<IInstanceRestorer.ILayout> {
-    return this._restored.promise;
+  get leftAreaIsEmpty(): boolean {
+    return this._leftHandler.stackedPanel.widgets.length === 0;
   }
 
   /**
@@ -175,6 +161,20 @@ class ApplicationShell extends Widget {
     return this._dockPanel.isEmpty;
   }
 
+  /**
+   * Promise that resolves when state is restored, returning layout description.
+   */
+  get restored(): Promise<IInstanceRestorer.ILayout> {
+    return this._restored.promise;
+  }
+
+  /**
+   * True if right area is empty.
+   */
+  get rightAreaIsEmpty(): boolean {
+    return this._rightHandler.stackedPanel.widgets.length === 0;
+  }
+
   /**
    * True if top area is empty.
    */
@@ -183,48 +183,106 @@ class ApplicationShell extends Widget {
   }
 
   /**
-   * True if left area is empty.
+   * Activate a widget in the left area.
    */
-  get leftAreaIsEmpty(): boolean {
-    return this._leftHandler.stackedPanel.widgets.length === 0;
+  activateLeft(id: string): void {
+    this._leftHandler.activate(id);
   }
 
   /**
-   * True if right area is empty.
+   * Activate a widget in the main area.
    */
-  get rightAreaIsEmpty(): boolean {
-    return this._rightHandler.stackedPanel.widgets.length === 0;
+  activateMain(id: string): void {
+    let dock = this._dockPanel;
+    let widget = find(dock.widgets(), value => value.id === id);
+    if (widget) {
+      dock.activateWidget(widget);
+    }
+  }
+
+  /*
+   * Activate the next Tab in the active TabBar.
+  */
+  activateNextTab(): void {
+    let current = this._currentTabBar();
+    if (current) {
+      let ci = current.currentIndex;
+      if (ci !== -1) {
+        if (ci < current.titles.length - 1) {
+          current.currentIndex += 1;
+          current.currentTitle.owner.activate();
+        } else if (ci === current.titles.length - 1) {
+          let nextBar = this._nextTabBar();
+          if (nextBar) {
+            nextBar.currentIndex = 0;
+            nextBar.currentTitle.owner.activate();
+          }
+        }
+      }
+    }
+  }
+
+  /*
+   * Activate the previous Tab in the active TabBar.
+  */
+  activatePreviousTab(): void {
+    let current = this._currentTabBar();
+    if (current) {
+      let ci = current.currentIndex;
+      if (ci !== -1) {
+        if (ci > 0) {
+          current.currentIndex -= 1;
+          current.currentTitle.owner.activate();
+        } else if (ci === 0) {
+          let prevBar = this._previousTabBar();
+          if (prevBar) {
+            let len = prevBar.titles.length;
+            prevBar.currentIndex = len - 1;
+            prevBar.currentTitle.owner.activate();
+          }
+        }
+      }
+    }
   }
 
   /**
-   * Add a widget to the top content area.
+   * Activate a widget in the right area.
+   */
+  activateRight(id: string): void {
+    this._rightHandler.activate(id);
+  }
+
+  /**
+   * Add a widget to the left content area.
    *
    * #### Notes
    * Widgets must have a unique `id` property, which will be used as the DOM id.
    */
-  addToTopArea(widget: Widget, options: ApplicationShell.ISideAreaOptions = {}): void {
+  addToLeftArea(widget: Widget, options: ApplicationShell.ISideAreaOptions = {}): void {
     if (!widget.id) {
       console.error('widgets added to app shell must have unique id property');
       return;
     }
-    // Temporary: widgets are added to the panel in order of insertion.
-    this._topPanel.addWidget(widget);
+    let rank = 'rank' in options ? options.rank : 100;
+    this._leftHandler.addWidget(widget, rank);
     this._save();
   }
 
   /**
-   * Add a widget to the left content area.
+   * Add a widget to the main content area.
    *
    * #### Notes
    * Widgets must have a unique `id` property, which will be used as the DOM id.
+   * All widgets added to the main area should be disposed after removal (or
+   * simply disposed in order to remove).
    */
-  addToLeftArea(widget: Widget, options: ApplicationShell.ISideAreaOptions = {}): void {
+  addToMainArea(widget: Widget): void {
     if (!widget.id) {
       console.error('widgets added to app shell must have unique id property');
       return;
     }
-    let rank = 'rank' in options ? options.rank : 100;
-    this._leftHandler.addWidget(widget, rank);
+    this._dockPanel.addWidget(widget, { mode: 'tab-after' });
+    this._tracker.add(widget);
     this._save();
   }
 
@@ -245,45 +303,21 @@ class ApplicationShell extends Widget {
   }
 
   /**
-   * Add a widget to the main content area.
+   * Add a widget to the top content area.
    *
    * #### Notes
    * Widgets must have a unique `id` property, which will be used as the DOM id.
    */
-  addToMainArea(widget: Widget): void {
+  addToTopArea(widget: Widget, options: ApplicationShell.ISideAreaOptions = {}): void {
     if (!widget.id) {
       console.error('widgets added to app shell must have unique id property');
       return;
     }
-    this._dockPanel.addWidget(widget, { mode: 'tab-after' });
+    // Temporary: widgets are added to the panel in order of insertion.
+    this._topPanel.addWidget(widget);
     this._save();
   }
 
-  /**
-   * Activate a widget in the left area.
-   */
-  activateLeft(id: string): void {
-    this._leftHandler.activate(id);
-  }
-
-  /**
-   * Activate a widget in the right area.
-   */
-  activateRight(id: string): void {
-    this._rightHandler.activate(id);
-  }
-
-  /**
-   * Activate a widget in the main area.
-   */
-  activateMain(id: string): void {
-    let dock = this._dockPanel;
-    let widget = find(dock.widgets(), value => value.id === id);
-    if (widget) {
-      dock.activateWidget(widget);
-    }
-  }
-
   /**
    * Collapse the left area.
    */
@@ -304,55 +338,10 @@ class ApplicationShell extends Widget {
    * Close all widgets in the main area.
    */
   closeAll(): void {
-    each(toArray(this._dockPanel.widgets()), widget => { widget.close(); });
+    each(this._dockPanel.widgets(), widget => { widget.close(); });
     this._save();
   }
 
-  /*
-   * Activate the next Tab in the active TabBar.
-  */
-  activateNextTab(): void {
-    let current = this._currentTabBar();
-    if (current) {
-      let ci = current.currentIndex;
-      if (ci !== -1) {
-        if (ci < current.titles.length - 1) {
-          current.currentIndex += 1;
-          current.currentTitle.owner.activate();
-        } else if (ci === current.titles.length - 1) {
-          let nextBar = this._nextTabBar();
-          if (nextBar) {
-            nextBar.currentIndex = 0;
-            nextBar.currentTitle.owner.activate();
-          }
-        }
-      }
-    }
-  }
-
-  /*
-   * Activate the previous Tab in the active TabBar.
-  */
-  activatePreviousTab(): void {
-    let current = this._currentTabBar();
-    if (current) {
-      let ci = current.currentIndex;
-      if (ci !== -1) {
-        if (ci > 0) {
-          current.currentIndex -= 1;
-          current.currentTitle.owner.activate();
-        } else if (ci === 0) {
-          let prevBar = this._previousTabBar();
-          if (prevBar) {
-            let len = prevBar.titles.length;
-            prevBar.currentIndex = len - 1;
-            prevBar.currentTitle.owner.activate();
-          }
-        }
-      }
-    }
-  }
-
   /**
    * Set the layout data store for the application shell.
    */
@@ -381,7 +370,7 @@ class ApplicationShell extends Widget {
       return this._save().then(() => { this._restored.resolve(saved); });
     });
     // Catch current changed events on the side handlers.
-    this._dockPanel.currentChanged.connect(this._save, this);
+    this._tracker.currentChanged.connect(this._save, this);
     this._leftHandler.sideBar.currentChanged.connect(this._save, this);
     this._rightHandler.sideBar.currentChanged.connect(this._save, this);
   }
@@ -389,11 +378,13 @@ class ApplicationShell extends Widget {
   /*
    * Return the TabBar that has the currently active Widget or undefined.
    */
-  private _currentTabBar(): TabBar {
-    let current = this._dockPanel.currentWidget;
+  private _currentTabBar(): TabBar<Widget> {
+    let current = this._tracker.currentWidget;
     if (current) {
       let title = current.title;
-      let tabBar = find(this._dockPanel.tabBars(), bar => contains(bar.titles, title));
+      let tabBar = find(this._dockPanel.tabBars(), bar => {
+        return ArrayExt.firstIndexOf(bar.titles, title) > -1;
+      });
       return tabBar;
     }
     return void 0;
@@ -402,13 +393,13 @@ class ApplicationShell extends Widget {
   /*
    * Return the TabBar previous to the current TabBar (see above) or undefined.
    */
-  private _previousTabBar(): TabBar {
+  private _previousTabBar(): TabBar<Widget> {
     let current = this._currentTabBar();
     if (current) {
       let bars = toArray(this._dockPanel.tabBars());
       let len = bars.length;
-      let ci = bars.ArrayExt.firstIndexOf(current);
-      let prevBar: TabBar = null;
+      let ci = ArrayExt.firstIndexOf(bars, current);
+      let prevBar: TabBar<Widget> = null;
       if (ci > 0) {
         prevBar = bars[ci - 1];
       } else if (ci === 0) {
@@ -422,13 +413,13 @@ class ApplicationShell extends Widget {
   /*
    * Return the TabBar next to the current TabBar (see above) or undefined.
    */
-  private _nextTabBar(): TabBar {
+  private _nextTabBar(): TabBar<Widget> {
     let current = this._currentTabBar();
     if (current) {
       let bars = toArray(this._dockPanel.tabBars());
       let len = bars.length;
-      let ci = bars.ArrayExt.firstIndexOf(current);
-      let nextBar: TabBar = null;
+      let ci = ArrayExt.firstIndexOf(bars, current);
+      let nextBar: TabBar<Widget> = null;
       if (ci < (len - 1)) {
         nextBar = bars[ci + 1];
       } else if (ci === len - 1) {
@@ -449,7 +440,7 @@ class ApplicationShell extends Widget {
     }
 
     let data: IInstanceRestorer.ILayout = {
-      currentWidget: this._dockPanel.currentWidget,
+      currentWidget: this._tracker.currentWidget,
       leftArea: this._leftHandler.dehydrate(),
       rightArea: this._rightHandler.dehydrate()
     };
@@ -459,7 +450,7 @@ class ApplicationShell extends Widget {
   /**
    * Handle a change to the dock area current widget.
    */
-  private _onCurrentChanged(sender: DockPanel, args: DockPanel.ICurrentChangedArgs): void {
+  private _onCurrentChanged(sender: any, args: FocusTracker.IChangedArgs<Widget>): void {
     if (args.newValue) {
       args.newValue.title.className += ` ${CURRENT_CLASS}`;
     }
@@ -467,25 +458,21 @@ class ApplicationShell extends Widget {
       let title = args.oldValue.title;
       title.className = title.className.replace(CURRENT_CLASS, '');
     }
-    this.currentChanged.emit(args);
   }
 
   private _database: IInstanceRestorer.ILayoutDB = null;
   private _dockPanel: DockPanel;
-  private _isRestored = false;
   private _hboxPanel: BoxPanel;
   private _hsplitPanel: SplitPanel;
+  private _isRestored = false;
   private _leftHandler: Private.SideBarHandler;
   private _restored = new utils.PromiseDelegate<IInstanceRestorer.ILayout>();
   private _rightHandler: Private.SideBarHandler;
   private _topPanel: Panel;
+  private _tracker = new FocusTracker<Widget>();
 }
 
 
-// Define the signals for the `ApplicationShell` class.
-defineSignal(ApplicationShell.prototype, 'currentChanged');
-
-
 /**
  * The namespace for `ApplicationShell` class statics.
  */
@@ -545,7 +532,7 @@ namespace Private {
      */
     constructor(side: string) {
       this._side = side;
-      this._sideBar = new TabBar({
+      this._sideBar = new TabBar<Widget>({
         insertBehavior: 'none',
         removeBehavior: 'none',
         allowDeselect: true
@@ -561,7 +548,7 @@ namespace Private {
     /**
      * Get the tab bar managed by the handler.
      */
-    get sideBar(): TabBar {
+    get sideBar(): TabBar<Widget> {
       return this._sideBar;
     }
 
@@ -602,7 +589,7 @@ namespace Private {
       widget.hide();
       let item = { widget, rank };
       let index = this._findInsertIndex(item);
-      this._items.insert(index, item);
+      ArrayExt.insert(this._items, index, item);
       this._stackedPanel.insertWidget(index, widget);
       this._sideBar.insertTab(index, widget.title);
       this._refreshVisibility();
@@ -646,7 +633,7 @@ namespace Private {
     /**
      * Find the widget which owns the given title, or `null`.
      */
-    private _findWidgetByTitle(title: Title): Widget {
+    private _findWidgetByTitle(title: Title<Widget>): Widget {
       let item = find(this._items, value => value.widget.title === title);
       return item ? item.widget : null;
     }
@@ -670,7 +657,7 @@ namespace Private {
     /**
      * Handle the `currentChanged` signal from the sidebar.
      */
-    private _onCurrentChanged(sender: TabBar, args: TabBar.ICurrentChangedArgs): void {
+    private _onCurrentChanged(sender: TabBar<Widget>, args: TabBar.ICurrentChangedArgs<Widget>): void {
       let oldWidget = this._findWidgetByTitle(args.previousTitle);
       let newWidget = this._findWidgetByTitle(args.currentTitle);
       if (oldWidget) {
@@ -690,7 +677,7 @@ namespace Private {
     /**
      * Handle a `tabActivateRequest` signal from the sidebar.
      */
-    private _onTabActivateRequested(sender: TabBar, args: TabBar.ITabActivateRequestedArgs): void {
+    private _onTabActivateRequested(sender: TabBar<Widget>, args: TabBar.ITabActivateRequestedArgs<Widget>): void {
       args.title.owner.activate();
     }
 
@@ -698,14 +685,14 @@ namespace Private {
      * Handle the `widgetRemoved` signal from the stacked panel.
      */
     private _onWidgetRemoved(sender: StackedPanel, widget: Widget): void {
-      this._items.removeAt(this._findWidgetIndex(widget));
+      ArrayExt.removeAt(this._items, this._findWidgetIndex(widget));
       this._sideBar.removeTab(widget.title);
       this._refreshVisibility();
     }
 
+    private _items = new Array<Private.IRankItem>();
     private _side: string;
-    private _sideBar: TabBar;
+    private _sideBar: TabBar<Widget>;
     private _stackedPanel: StackedPanel;
-    private _items = new Vector<Private.IRankItem>();
   }
 }