Quellcode durchsuchen

Fixed up "open with...", now behaves same as original

telamonian vor 6 Jahren
Ursprung
Commit
0b920565b3
2 geänderte Dateien mit 50 neuen und 169 gelöschten Zeilen
  1. 4 55
      packages/docregistry/src/registry.ts
  2. 46 114
      packages/filebrowser-extension/src/index.ts

+ 4 - 55
packages/docregistry/src/registry.ts

@@ -410,63 +410,12 @@ export class DocumentRegistry implements IDisposable {
   /**
    * Create an iterator over the widget factories that have been registered.
    *
-   * @param preferredOrder - If this flag is set, the return value will
-   * iterate over the widget factories using the same ordering as
-   * [[preferredWidgetFactories]].
-   *
    * @returns A new iterator of widget factories.
    */
-  widgetFactories(
-    preferredOrder: boolean = false
-  ): IIterator<DocumentRegistry.WidgetFactory> {
-    if (preferredOrder) {
-      let factoryNames = new Set<string>();
-
-      // Start with the file type default factoryNames.
-      Object.keys(this._defaultWidgetFactories).forEach(name => {
-        factoryNames.add(this._defaultWidgetFactories[name]);
-      });
-
-      // Add the file type default rendered factoryNames.
-      Object.keys(this._defaultRenderedWidgetFactories).forEach(name => {
-        factoryNames.add(this._defaultRenderedWidgetFactories[name]);
-      });
-
-      // Add the global default factory.
-      if (this._defaultWidgetFactory) {
-        factoryNames.add(this._defaultWidgetFactory);
-      }
-
-      // Add the file type factoryNames in registration order.
-      Object.keys(this._widgetFactoryExtensions).forEach(name => {
-        each(this._widgetFactoryExtensions[name], n => {
-          factoryNames.add(n);
-        });
-      });
-
-      // Add the rest of the global factoryNames, in registration order.
-      if ('*' in this._widgetFactoryExtensions) {
-        each(this._widgetFactoryExtensions['*'], n => {
-          factoryNames.add(n);
-        });
-      }
-
-      // Convert the set of factory names to an array of factories
-      let factories: DocumentRegistry.WidgetFactory[] = [];
-      factoryNames.forEach(name => {
-        let factory = this._widgetFactories[name];
-        if (!factory) {
-          return;
-        }
-        factories.push(factory);
-      });
-
-      return new ArrayIterator(factories);
-    } else {
-      return map(Object.keys(this._widgetFactories), name => {
-        return this._widgetFactories[name];
-      });
-    }
+  widgetFactories(): IIterator<DocumentRegistry.WidgetFactory> {
+    return map(Object.keys(this._widgetFactories), name => {
+      return this._widgetFactories[name];
+    });
   }
 
   /**

+ 46 - 114
packages/filebrowser-extension/src/index.ts

@@ -27,10 +27,12 @@ import {
 
 import { Launcher } from '@jupyterlab/launcher';
 
-import { each, every, map, toArray } from '@phosphor/algorithm';
+import { map, reduce, toArray } from '@phosphor/algorithm';
 
 import { CommandRegistry } from '@phosphor/commands';
 
+import { Message } from '@phosphor/messaging';
+
 import { Menu } from '@phosphor/widgets';
 
 /**
@@ -138,7 +140,6 @@ function activateFactory(
       model,
       commands: options.commands || commands
     });
-    // const { registry } = docManager;
 
     // Add a launcher toolbar item.
     let launcher = new ToolbarButton({
@@ -150,15 +151,6 @@ function activateFactory(
     });
     widget.toolbar.insertItem(0, 'launch', launcher);
 
-    // // Add a context menu handler to the file browser's directory listing.
-    // let node = widget.node.getElementsByClassName('jp-DirListing-content')[0];
-    // node.addEventListener('contextmenu', (event: MouseEvent) => {
-    //   event.preventDefault();
-    //   const model = widget.modelForClick(event);
-    //   const menu = createContextMenu(model, commands, registry);
-    //   menu.open(event.clientX, event.clientY);
-    // });
-
     // Track the newly created file browser.
     tracker.add(widget);
 
@@ -373,31 +365,6 @@ function addCommands(
       );
     },
     iconClass: 'jp-MaterialIcon jp-OpenFolderIcon',
-    isVisible: (args): boolean => {
-      if ('factory' in args) {
-        // when factory is explicitly passed, show only when relevant
-        const factory = args['factory'] as string;
-        const widget = tracker.currentWidget;
-
-        return every(
-          map(widget.selectedItems(), item => {
-            if (item.type === 'directory') {
-              return false;
-            }
-
-            return (
-              registry
-                .preferredWidgetFactories(item.path)
-                .map(f => f.name)
-                .indexOf(factory) > -1
-            );
-          }),
-          bool => bool
-        );
-      }
-
-      return true;
-    },
     label: args => (args['label'] || args['factory'] || 'Open') as string,
     mnemonic: 0
   });
@@ -564,6 +531,48 @@ function addCommands(
     execute: () => createLauncher(commands, browser)
   });
 
+  /**
+   * A menu widget that dynamically populates with different widget factories
+   * based on current filebrowser selection.
+   */
+  class OpenwithMenu extends Menu {
+    protected onBeforeAttach(msg: Message): void {
+      const widget = tracker.currentWidget;
+      let listings = widget.selectedItems();
+      let listing = listings.next();
+
+      // clear the current menu items
+      this.clearItems();
+
+      // listing will be undefined if widget.selectedItems() is empty
+      if (listing) {
+        // get the intersection of all the preferred factories in the current file browser selection
+        let factories = new Set(
+          registry.preferredWidgetFactories(listing.path)
+        );
+        factories = reduce(
+          listings,
+          (i, l) => {
+            return new Set(
+              registry.preferredWidgetFactories(l.path).filter(x => i.has(x))
+            );
+          },
+          factories
+        );
+
+        // make new menu items from the preferred factories
+        factories.forEach(factory => {
+          this.addItem({
+            args: { factory: factory.name },
+            command: CommandIDs.open
+          });
+        });
+      }
+
+      super.onBeforeAttach(msg);
+    }
+  }
+
   // matches anywhere on filebrowser that is not an item
   const selectorDeadSpace = '.jp-DirListing-deadSpace';
   // matches all filebrowser items
@@ -584,23 +593,7 @@ function addCommands(
     rank: 1
   });
 
-  // Create and populate the 'Open with' submenu
-  const openWith = new Menu({ commands });
-  openWith.title.label = 'Open With';
-
-  const updateOpenWith = (): void => {
-    openWith.clearItems();
-    each(registry.widgetFactories(true), factory => {
-      openWith.addItem({
-        args: { factory: factory.name },
-        command: CommandIDs.open
-      });
-    });
-  };
-  updateOpenWith();
-  // run again whenever the registry changes
-  registry.changed.connect(updateOpenWith);
-
+  const openWith = new OpenwithMenu({ commands });
   openWith.title.label = 'Open With';
   app.contextMenu.addItem({
     type: 'submenu',
@@ -676,67 +669,6 @@ function addCommands(
   });
 }
 
-// /**
-//  * Create a context menu for the file browser listing.
-//  *
-//  * #### Notes
-//  * This function generates temporary commands with an incremented name. These
-//  * commands are disposed when the menu itself is disposed.
-//  */
-// function createContextMenu(
-//   model: Contents.IModel | undefined,
-//   commands: CommandRegistry,
-//   registry: DocumentRegistry
-// ): Menu {
-//   const menu = new Menu({ commands });
-//
-//   // If the user did not click on any file, we still want to show
-//   // paste as a possibility.
-//   if (!model) {
-//     menu.addItem({ command: CommandIDs.paste });
-//     return menu;
-//   }
-//
-//   menu.addItem({ command: CommandIDs.open });
-//
-//   const path = model.path;
-//   if (model.type !== 'directory') {
-//     const factories = registry.preferredWidgetFactories(path).map(f => f.name);
-//     if (path && factories.length > 1) {
-//       const command = 'docmanager:open';
-//       const openWith = new Menu({ commands });
-//       openWith.title.label = 'Open With';
-//       factories.forEach(factory => {
-//         openWith.addItem({ args: { factory, path }, command });
-//       });
-//       menu.addItem({ type: 'submenu', submenu: openWith });
-//     }
-//     menu.addItem({ command: CommandIDs.openBrowserTab });
-//   }
-//
-//   menu.addItem({ command: CommandIDs.rename });
-//   menu.addItem({ command: CommandIDs.del });
-//   menu.addItem({ command: CommandIDs.cut });
-//
-//   if (model.type !== 'directory') {
-//     menu.addItem({ command: CommandIDs.copy });
-//   }
-//
-//   menu.addItem({ command: CommandIDs.paste });
-//
-//   if (model.type !== 'directory') {
-//     menu.addItem({ command: CommandIDs.duplicate });
-//     menu.addItem({ command: CommandIDs.download });
-//     menu.addItem({ command: CommandIDs.shutdown });
-//   }
-//
-//   menu.addItem({ command: CommandIDs.share });
-//   menu.addItem({ command: CommandIDs.copyPath });
-//   menu.addItem({ command: CommandIDs.copyDownloadLink });
-//
-//   return menu;
-// }
-
 /**
  * Create a launcher for a given filebrowser widget.
  */