Steven Silvester пре 8 година
родитељ
комит
18740944be
5 измењених фајлова са 58 додато и 87 уклоњено
  1. 19 10
      src/docmanager/manager.ts
  2. 2 21
      src/filebrowser/browser.ts
  3. 0 13
      src/filebrowser/buttons.ts
  4. 35 40
      src/filebrowser/listing.ts
  5. 2 3
      src/filebrowser/plugin.ts

+ 19 - 10
src/docmanager/manager.ts

@@ -64,9 +64,6 @@ class DocumentManager implements IDisposable {
 
   /**
    * Get the kernel spec models for the manager.
-   *
-   * #### Notes
-   * This is a read-only property.
    */
   get kernelspecs(): Kernel.ISpecModels {
     return this._serviceManager.kernelspecs;
@@ -74,9 +71,6 @@ class DocumentManager implements IDisposable {
 
   /**
    * Get the registry used by the manager.
-   *
-   * #### Notes
-   * This is a read-only property.
    */
   get registry(): DocumentRegistry {
     return this._registry;
@@ -130,7 +124,9 @@ class DocumentManager implements IDisposable {
       // Load the contents from disk.
       context.revert();
     }
-    return this._widgetManager.createWidget(widgetName, context, kernel);
+    let widget = this._widgetManager.createWidget(widgetName, context, kernel);
+    this._opener.open(widget);
+    return widget;
   }
 
   /**
@@ -154,7 +150,9 @@ class DocumentManager implements IDisposable {
     let context = this._createContext(path, factory);
     // Immediately save the contents to disk.
     context.save();
-    return this._widgetManager.createWidget(widgetName, context, kernel);
+    let widget = this._widgetManager.createWidget(widgetName, context, kernel);
+    this._opener.open(widget);
+    return widget;
   }
 
   /**
@@ -286,7 +284,7 @@ class DocumentManager implements IDisposable {
   private _widgetManager: DocumentWidgetManager = null;
   private _registry: DocumentRegistry = null;
   private _contexts: Vector<Context<DocumentRegistry.IModel>> = new Vector<Context<DocumentRegistry.IModel>>();
-  private _opener: FileBrowser.IWidgetOpener = null;
+  private _opener: DocumentManager.IWidgetOpener = null;
 }
 
 
@@ -313,7 +311,18 @@ namespace DocumentManager {
     /**
      * A widget opener for sibling widgets.
      */
-    opener: FileBrowser.IWidgetOpener;
+    opener: IWidgetOpener;
+  }
+
+  /**
+   * An interface for a widget opener.
+   */
+  export
+  interface IWidgetOpener {
+    /**
+     * Open the given widget.
+     */
+    open(widget: Widget): void;
   }
 }
 

+ 2 - 21
src/filebrowser/browser.ts

@@ -96,15 +96,14 @@ class FileBrowser extends Widget {
     let keymap = this._keymap = options.keymap;
     let manager = this._manager = options.manager;
     let model = this._model = options.model;
-    let opener = this._opener = options.opener;
     let renderer = options.renderer;
 
     model.refreshed.connect(this._handleRefresh, this);
     this._crumbs = new BreadCrumbs({ model });
     this._buttons = new FileButtons({
-      commands, keymap, manager, model, opener
+      commands, keymap, manager, model
     });
-    this._listing = new DirListing({ manager, model, opener, renderer });
+    this._listing = new DirListing({ manager, model, renderer });
 
     model.fileChanged.connect((fbModel, args) => {
       let oldPath = args.oldValue && args.oldValue.path || null;
@@ -158,7 +157,6 @@ class FileBrowser extends Widget {
     this._buttons = null;
     this._listing = null;
     this._manager = null;
-    this._opener = null;
     super.dispose();
   }
 
@@ -357,7 +355,6 @@ class FileBrowser extends Widget {
   private _listing: DirListing = null;
   private _manager: DocumentManager = null;
   private _model: FileBrowserModel = null;
-  private _opener: FileBrowser.IWidgetOpener = null;
   private _timeoutId = -1;
 }
 
@@ -392,11 +389,6 @@ namespace FileBrowser {
      */
     manager: DocumentManager;
 
-    /**
-     * A widget opener function.
-     */
-    opener: IWidgetOpener;
-
     /**
      * An optional renderer for the directory listing area.
      *
@@ -404,15 +396,4 @@ namespace FileBrowser {
      */
     renderer?: DirListing.IRenderer;
   }
-
-  /**
-   * An interface for a widget opener.
-   */
-  export
-  interface IWidgetOpener {
-    /**
-     * Open the given widget.
-     */
-    open(widget: Widget): void;
-  }
 }

+ 0 - 13
src/filebrowser/buttons.ts

@@ -37,10 +37,6 @@ import {
   DocumentManager
 } from '../docmanager';
 
-import {
-  FileBrowser
-} from './browser';
-
 import {
   createFromDialog
 } from './dialogs';
@@ -125,7 +121,6 @@ class FileButtons extends Widget {
     this._commands = options.commands;
     this._keymap = options.keymap;
     this._manager = options.manager;
-    this._opener = options.opener;
   }
 
   /**
@@ -138,7 +133,6 @@ class FileButtons extends Widget {
     this._keymap = null;
     this._manager = null;
     this._model = null;
-    this._opener = null;
     super.dispose();
   }
 
@@ -208,7 +202,6 @@ class FileButtons extends Widget {
    * Open a widget and attach listeners.
    */
   private _open(widget: Widget): Widget {
-    this._opener.open(widget);
     let context = this._manager.contextForWidget(widget);
     context.populated.connect(() => this.model.refresh() );
     context.kernelChanged.connect(() => this.model.refresh() );
@@ -293,7 +286,6 @@ class FileButtons extends Widget {
   private _keymap: Keymap = null;
   private _manager: DocumentManager = null;
   private _model: FileBrowserModel;
-  private _opener: FileBrowser.IWidgetOpener = null;
 }
 
 
@@ -326,11 +318,6 @@ namespace FileButtons {
      * A document manager instance.
      */
     manager: DocumentManager;
-
-    /**
-     * A widget opener function.
-     */
-    opener: FileBrowser.IWidgetOpener;
   }
 }
 

+ 35 - 40
src/filebrowser/listing.ts

@@ -6,17 +6,21 @@ import {
 } from '@jupyterlab/services';
 
 import {
-  each
+  each, filter, map, toArray
 } from 'phosphor/lib/algorithm/iteration';
 
 import {
-  find, findIndex
+  find, findIndex, indexOf
 } from 'phosphor/lib/algorithm/searching';
 
 import {
   ISequence
 } from 'phosphor/lib/algorithm/sequence';
 
+import {
+  Vector
+} from 'phosphor/lib/collections/vector';
+
 import {
   Message
 } from 'phosphor/lib/core/messaging';
@@ -49,10 +53,6 @@ import {
   DocumentManager
 } from '../docmanager';
 
-import {
-  FileBrowser
-} from './browser';
-
 import {
   renameFile
 } from './dialogs';
@@ -216,7 +216,6 @@ class DirListing extends Widget {
     this._editNode = document.createElement('input');
     this._editNode.className = EDITOR_CLASS;
     this._manager = options.manager;
-    this._opener = options.opener;
     this._renderer = options.renderer || DirListing.defaultRenderer;
     let headerNode = utils.findElement(this.node, HEADER_CLASS);
     this._renderer.populateHeaderNode(headerNode);
@@ -232,7 +231,6 @@ class DirListing extends Widget {
     this._drag = null;
     this._dragData = null;
     this._manager = null;
-    this._opener = null;
     super.dispose();
   }
 
@@ -292,6 +290,7 @@ class DirListing extends Widget {
    * Sort the items using a sort condition.
    */
   sort(state: DirListing.ISortState): void {
+    this._sortedModels.clear();
     this._sortedModels = Private.sort(this.model.items, state);
     this._sortState = state;
     this.update();
@@ -421,10 +420,10 @@ class DirListing extends Widget {
   shutdownKernels(): Promise<void> {
     let promises: Promise<void>[] = [];
     let items = this.sortedItems;
-    let paths = items.map(item => item.path);
+    let paths = toArray(map(items, item => item.path));
     each(this._model.sessions, session => {
-      let index = paths.indexOf(session.notebook.path);
-      if (this._selection[items[index].name]) {
+      let index = indexOf(paths, session.notebook.path);
+      if (this._selection[items.at(index).name]) {
         promises.push(this._model.shutdown(session.id));
       }
     });
@@ -516,7 +515,7 @@ class DirListing extends Widget {
     let items = this.sortedItems;
     let index = utils.hitTestNodes(this._items, event.clientX, event.clientY);
     if (index !== -1) {
-      return items[index].path;
+      return items.at(index).path;
     }
   }
 
@@ -649,8 +648,8 @@ class DirListing extends Widget {
 
     // Add extra classes to item nodes based on widget state.
     for (let i = 0, n = items.length; i < n; ++i) {
-      renderer.updateItemNode(nodes[i], items[i]);
-      if (this._selection[items[i].name]) {
+      renderer.updateItemNode(nodes[i], items.at(i));
+      if (this._selection[items.at(i).name]) {
         nodes[i].classList.add(SELECTED_CLASS);
         if (this._isCut && this._model.path === this._prevPath) {
           nodes[i].classList.add(CUT_CLASS);
@@ -668,10 +667,10 @@ class DirListing extends Widget {
     }
 
     // Handle notebook session statuses.
-    let paths = items.map(item => item.path);
+    let paths = toArray(map(items, item => item.path));
     let specs = this._model.kernelspecs;
     each(this._model.sessions, session => {
-      let index = paths.indexOf(session.notebook.path);
+      let index = indexOf(paths, session.notebook.path);
       let node = this._items[index];
       node.classList.add(RUNNING_CLASS);
       node.title = specs.kernelspecs[session.kernel.name].spec.display_name;
@@ -858,7 +857,7 @@ class DirListing extends Widget {
     }
 
     let model = this._model;
-    let item = this.sortedItems[i];
+    let item = this.sortedItems.at(i);
     if (item.type === 'directory') {
       model.cd(item.name).catch(error =>
         showErrorMessage(this, 'Open directory', error)
@@ -872,7 +871,6 @@ class DirListing extends Widget {
         context.populated.connect(() => model.refresh() );
         context.kernelChanged.connect(() => model.refresh() );
       }
-      this._opener.open(widget);
     }
   }
 
@@ -886,7 +884,7 @@ class DirListing extends Widget {
       if (index === -1) {
         return;
       }
-      let item = this.sortedItems[index];
+      let item = this.sortedItems.at(index);
       if (item.type !== 'directory' || this._selection[item.name]) {
         return;
       }
@@ -952,7 +950,7 @@ class DirListing extends Widget {
     // Get the path based on the target node.
     let index = this._items.indexOf(target);
     let items = this.sortedItems;
-    let path = items[index].name + '/';
+    let path = items.at(index).name + '/';
 
     // Move all of the items.
     let promises: Promise<Contents.IModel>[] = [];
@@ -979,7 +977,7 @@ class DirListing extends Widget {
 
     // If the source node is not selected, use just that node.
     if (!source.classList.contains(SELECTED_CLASS)) {
-      item = items[index];
+      item = items.at(index);
       selectedNames = [item.name];
     } else if (selectedNames.length === 1) {
       let name = selectedNames[0];
@@ -1007,7 +1005,6 @@ class DirListing extends Widget {
           context.populated.connect(() => model.refresh() );
           context.kernelChanged.connect(() => model.refresh() );
         }
-        this._opener.open(widget);
         return widget;
       });
     }
@@ -1039,7 +1036,7 @@ class DirListing extends Widget {
     // Clear any existing soft selection.
     this._softSelection = '';
 
-    let name = items[index].name;
+    let name = items.at(index).name;
     let selected = Object.keys(this._selection);
 
     // Handle toggling.
@@ -1087,7 +1084,7 @@ class DirListing extends Widget {
       if (i === index) {
         continue;
       }
-      let name = items[i].name;
+      let name = items.at(i).name;
       if (selected.indexOf(name) !== -1) {
         if (nearestIndex === -1) {
           nearestIndex = i;
@@ -1108,7 +1105,7 @@ class DirListing extends Widget {
     for (let i = 0; i < this._items.length; i++) {
       if (nearestIndex >= i && index <= i ||
           nearestIndex <= i && index >= i) {
-        this._selection[items[i].name] = true;
+        this._selection[items.at(i).name] = true;
       }
     }
   }
@@ -1118,7 +1115,7 @@ class DirListing extends Widget {
    */
   private _getSelectedItems(): Contents.IModel[] {
     let items = this.sortedItems;
-    return items.filter(item => this._selection[item.name]);
+    return toArray(filter(items, item => this._selection[item.name]));
   }
 
   /**
@@ -1157,7 +1154,7 @@ class DirListing extends Widget {
     let name = Object.keys(this._selection)[0];
     let index = findIndex(items, value => value.name === name);
     let row = this._items[index];
-    let item = items[index];
+    let item = items.at(index);
     let nameNode = this.renderer.getNameNode(row);
     let original = item.name;
     this._editNode.value = original;
@@ -1185,7 +1182,7 @@ class DirListing extends Widget {
     if (!keepExisting) {
       this._selection = Object.create(null);
     }
-    let name = items[index].name;
+    let name = items.at(index).name;
     this._selection[name] = true;
     scrollIntoViewIfNeeded(this.contentNode, this._items[index]);
     this._isCut = false;
@@ -1231,7 +1228,6 @@ class DirListing extends Widget {
   private _prevPath = '';
   private _clipboard: string[] = [];
   private _manager: DocumentManager = null;
-  private _opener: FileBrowser.IWidgetOpener = null;
   private _softSelection = '';
   private _inContext = false;
   private _selection: { [key: string]: boolean; } = Object.create(null);
@@ -1259,11 +1255,6 @@ namespace DirListing {
      */
     manager: DocumentManager;
 
-    /**
-     * A widget opener function.
-     */
-    opener: FileBrowser.IWidgetOpener;
-
     /**
      * A renderer for file items.
      *
@@ -1607,11 +1598,14 @@ namespace Private {
    * Sort a list of items by sort state as a new array.
    */
   export
-  function sort(items: ISequence<Contents.IModel>, state: DirListing.ISortState) : Contents.IModel[] {
-    let copy: Contents.IModel[] = [];
-    each(items, item => {
-      copy.push(item);
-    });
+  function sort(items: ISequence<Contents.IModel>, state: DirListing.ISortState) : Vector<Contents.IModel> {
+    // Shortcut for unmodified.
+    if (state.key !== 'last_modified' && state.direction === 'ascending') {
+      return new Vector(items);
+    }
+
+    let copy = toArray(items);
+
     if (state.key === 'last_modified') {
       copy.sort((a, b) => {
         let valA = new Date(a.last_modified).getTime();
@@ -1624,6 +1618,7 @@ namespace Private {
     if (state.direction === 'descending') {
       copy.reverse();
     }
-    return copy;
+
+    return new Vector(copy);
   }
 }

+ 2 - 3
src/filebrowser/plugin.ts

@@ -89,7 +89,7 @@ const tracker = new InstanceTracker<Widget>();
  */
 function activateFileBrowser(app: JupyterLab, manager: IServiceManager, registry: IDocumentRegistry, mainMenu: IMainMenu, palette: ICommandPalette): IPathTracker {
   let id = 0;
-  let opener: FileBrowser.IWidgetOpener = {
+  let opener: DocumentManager.IWidgetOpener = {
     open: widget => {
       if (!widget.id) {
         widget.id = `document-manager-${++id}`;
@@ -108,8 +108,7 @@ function activateFileBrowser(app: JupyterLab, manager: IServiceManager, registry
     commands: commands,
     keymap: keymap,
     manager: docManager,
-    model: fbModel,
-    opener: opener
+    model: fbModel
   });
 
   let category = 'File Operations';