浏览代码

Merge pull request #339 from blink1073/open-with

Add "Open with" to the file browser context menu
Jason Grout 8 年之前
父节点
当前提交
7bbc2613ff
共有 5 个文件被更改,包括 68 次插入7 次删除
  1. 1 0
      src/dialog/theme.css
  2. 16 0
      src/docmanager/context.ts
  3. 9 2
      src/filebrowser/browser.ts
  4. 14 0
      src/filebrowser/listing.ts
  5. 28 5
      src/filebrowser/plugin.ts

+ 1 - 0
src/dialog/theme.css

@@ -16,6 +16,7 @@
   width: 300px;
   box-sizing: border-box;
   box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.5);
+  word-wrap: break-word;
 }
 
 

+ 16 - 0
src/docmanager/context.ts

@@ -20,6 +20,10 @@ import {
   Widget
 } from 'phosphor-widget';
 
+import {
+  showDialog, okButton
+} from '../dialog';
+
 import {
   IDocumentContext, IDocumentModel, IModelFactory
 } from '../docregistry';
@@ -435,6 +439,12 @@ class ContextManager implements IDisposable {
     return this._contentsManager.save(path, contents).then(newContents => {
       contextEx.contentsModel = this._copyContentsModel(newContents);
       model.dirty = false;
+    }).catch(err => {
+      showDialog({
+        title: 'File Save Error',
+        body: err.xhr.responseText,
+        buttons: [okButton]
+      });
     });
   }
 
@@ -482,6 +492,12 @@ class ContextManager implements IDisposable {
       contextEx.contentsModel = contentsModel;
       contextEx.context.contentsModelChanged.emit(contentsModel);
       model.dirty = false;
+    }).catch(err => {
+      showDialog({
+        title: 'File Load Error',
+        body: err.xhr.responseText,
+        buttons: [okButton]
+      });
     });
   }
 

+ 9 - 2
src/filebrowser/browser.ts

@@ -182,11 +182,11 @@ class FileBrowserWidget extends Widget {
   /**
    * Open a file by path.
    */
-  openPath(path: string): Widget {
+  openPath(path: string, widgetName='default'): Widget {
     let model = this.model;
     let widget = this._manager.findWidget(path);
     if (!widget) {
-      widget = this._manager.open(path);
+      widget = this._manager.open(path, widgetName);
       let context = this._manager.contextForWidget(widget);
       context.populated.connect(() => model.refresh() );
       context.kernelChanged.connect(() => model.refresh() );
@@ -289,6 +289,13 @@ class FileBrowserWidget extends Widget {
     this._listing.selectPrevious();
   }
 
+  /**
+   * Find a path given a click.
+   */
+  pathForClick(event: MouseEvent): string {
+    return this._listing.pathForClick(event);
+  }
+
   /**
    * A message handler invoked on an `'after-attach'` message.
    */

+ 14 - 0
src/filebrowser/listing.ts

@@ -496,9 +496,23 @@ class DirListing extends Widget {
    * Get whether an item is selected by name.
    */
   isSelected(name: string): boolean {
+    if (this._softSelection) {
+      return name === this._softSelection;
+    }
     return this._selection[name] === true;
   }
 
+  /**
+   * Find a path given a click.
+   */
+  pathForClick(event: MouseEvent): string {
+    let items = this.sortedItems;
+    let index = utils.hitTestNodes(this._items, event.clientX, event.clientY);
+    if (index !== -1) {
+      return items[index].path;
+    }
+  }
+
   /**
    * Handle the DOM events for the directory listing.
    *

+ 28 - 5
src/filebrowser/plugin.ts

@@ -107,7 +107,6 @@ function activateFileBrowser(app: Application, provider: ServiceManager, registr
     manager: docManager,
     opener
   });
-  let menu = createMenu(fbWidget);
 
   // Add a context menu to the dir listing.
   let node = fbWidget.node.getElementsByClassName('jp-DirListing-content')[0];
@@ -115,6 +114,21 @@ function activateFileBrowser(app: Application, provider: ServiceManager, registr
     event.preventDefault();
     let x = event.clientX;
     let y = event.clientY;
+    let path = fbWidget.pathForClick(event);
+    let ext = '.' + path.split('.').pop();
+    let widgetNames = registry.listWidgetFactories(ext);
+    let items: MenuItem[] = [];
+    if (widgetNames.length > 1) {
+      for (let widgetName of widgetNames) {
+        items.push(new MenuItem({
+          text: widgetName,
+          handler: () => {
+            fbWidget.openPath(path, widgetName);
+          }
+        }));
+      }
+    }
+    let menu = createMenu(fbWidget, items);
     menu.popup(x, y);
   });
 
@@ -293,14 +307,22 @@ function activateFileBrowser(app: Application, provider: ServiceManager, registr
 /**
  * Create a context menu for the file browser listing.
  */
-function createMenu(fbWidget: FileBrowserWidget):  Menu {
-  return new Menu([
+function createMenu(fbWidget: FileBrowserWidget, openWith: MenuItem[]):  Menu {
+  let items = [
     new MenuItem({
       text: '&Open',
       icon: 'fa fa-folder-open-o',
       shortcut: 'Ctrl+O',
       handler: () => { fbWidget.open(); }
-    }),
+    })
+  ];
+  if (openWith.length) {
+    items.push(new MenuItem({
+      text: 'Open With...',
+      submenu: new Menu(openWith)
+    }));
+  }
+  items.push(
     new MenuItem({
       text: '&Rename',
       icon: 'fa fa-edit',
@@ -346,5 +368,6 @@ function createMenu(fbWidget: FileBrowserWidget):  Menu {
       icon: 'fa fa-stop-circle-o',
       handler: () => { fbWidget.shutdownKernels(); }
     })
-  ]);
+  );
+  return new Menu(items);
 }