浏览代码

wip refactor mime renderer extensions

Steven Silvester 7 年之前
父节点
当前提交
e8f56ad0ce

+ 34 - 22
packages/application/src/index.ts

@@ -5,6 +5,10 @@ import {
   CommandLinker
 } from '@jupyterlab/apputils';
 
+import {
+  Base64ModelFactory, DocumentRegistry, TextModelFactory
+} from '@jupyterlab/docregistry';
+
 import {
   IRenderMime, RenderMime,
   HTMLRenderer, LatexRenderer, ImageRenderer, TextRenderer,
@@ -15,6 +19,10 @@ import {
   Application, IPlugin
 } from '@phosphor/application';
 
+import {
+  createRendermimePlugins
+} from './mimerenderers';
+
 import {
   ApplicationShell
 } from './shell';
@@ -61,8 +69,29 @@ class JupyterLab extends Application<ApplicationShell> {
       }
     };
     this.rendermime = new RenderMime({ items, linkHandler });
+
+    let registry = this.docregistry = new DocumentRegistry();
+    registry.addModelFactory(new TextModelFactory());
+    registry.addModelFactory(new Base64ModelFactory());
+    registry.addFileType({
+      name: 'Text',
+      extension: '.txt',
+      contentType: 'file',
+      fileFormat: 'text'
+    });
+    registry.addCreator({ name: 'Text File', fileType: 'Text', });
+
+    if (options.mimeRenderers) {
+      let plugins = createRendermimePlugins(options.mimeRenderers);
+      plugins.forEach(plugin => { this.registerPlugin(plugin); });
+    }
   }
 
+  /**
+   * The document registry instance used by the application.
+   */
+  readonly docregistry: DocumentRegistry;
+
   /**
    * The rendermime instance used by the application.
    */
@@ -116,28 +145,6 @@ class JupyterLab extends Application<ApplicationShell> {
     mods.forEach(mod => { this.registerPluginModule(mod); });
   }
 
-  /**
-   * Register a rendermime extension module.
-   */
-  registerMimeModule(mod: IRenderMime.IExtensionModule): void {
-    let data = mod.default;
-    // Handle commonjs exports.
-    if (!mod.hasOwnProperty('__esModule')) {
-      data = mod as any;
-    }
-    if (!Array.isArray(data)) {
-      data = [data];
-    }
-    let rendermime = this.rendermime;
-
-    data.forEach(item => {
-      rendermime.addRenderer({
-        mimeType: item.mimeType,
-        renderer: item.renderer
-      }, item.rendererIndex || 0);
-    });
-  }
-
   private _info: JupyterLab.IInfo;
 }
 
@@ -187,6 +194,11 @@ namespace JupyterLab {
      * The assets directory of the app on the server.
      */
     assetsDir?: string;
+
+    /**
+     * The mime renderer extensions.
+     */
+    mimeRenderers?: IRenderMime.IExtensionModule[];
   }
 
   /**

+ 2 - 67
packages/application/src/layoutrestorer.ts

@@ -27,10 +27,6 @@ import {
   IStateDB
 } from '@jupyterlab/coreutils';
 
-import {
-  DocumentRegistry
-} from '@jupyterlab/docregistry';
-
 import {
   ApplicationShell
 } from '.';
@@ -68,14 +64,7 @@ interface ILayoutRestorer {
    *
    * @param options - The restoration options.
    */
-  restoreTracker(tracker: InstanceTracker<any>, options: ILayoutRestorer.IRestoreOptions<any>): void;
-
-  /**
-   * Restore the widgets of a particular widget factory.
-   *
-   * @param factory - The factory whose widgets will be restored.
-   */
-  restoreWidgetFactory(factory: DocumentRegistry.IWidgetFactory): void;
+  restore(tracker: InstanceTracker<any>, options: ILayoutRestorer.IRestoreOptions<any>): void;
 }
 
 
@@ -246,7 +235,7 @@ class LayoutRestorer implements ILayoutRestorer {
    *
    * @param options - The restoration options.
    */
-  restoreTracker(tracker: InstanceTracker<Widget>, options: ILayoutRestorer.IRestoreOptions<Widget>): Promise<any> {
+  restore(tracker: InstanceTracker<Widget>, options: ILayoutRestorer.IRestoreOptions<Widget>): Promise<any> {
     if (!this._promises) {
       const warning = 'restore() can only be called before `first` has resolved.';
       console.warn(warning);
@@ -285,60 +274,6 @@ class LayoutRestorer implements ILayoutRestorer {
     return promise;
   }
 
-  /**
-   * Restore the widgets of a particular widget factory.
-   *
-   * @param factory - The factory whose widgets will be restored.
-   */
-  restoreWidgetFactory(factory: DocumentRegistry.IWidgetFactory): void {
-    if (!this._promises) {
-      const warning = 'restore() can only be called before `first` has resolved.';
-      console.warn(warning);
-      return Promise.reject(warning);
-    }
-    let state = this._state;
-
-    // Whenever a new widget is added to the tracker, record its name.
-    factory.widgetCreated.connect((sender, widget) => {
-      let name = `${factory.name}:${widget.context.path}`;
-      let data = {
-        path: widget.context.path,
-        factory: factory.name;
-      };
-      this.add(widget, name);
-      state.save(name, { data });
-
-      // Update the widget name when the path changes.
-      widget.context.pathChanged.connect(() => {
-        let newName = `${factory.name}:${widget.context.path}`;
-        Private.nameProperty.set(widget, newName);
-        this._widgets.set(newName, widget);
-        state.remove(name);
-        data = {
-          path: widget.context.path,
-          factory: factory.name;
-        };
-        state.save(newName, { data });
-        name = newName;
-      }, this);
-    }, this);
-
-    let promises = [state.fetchNamespace(factory.name)];
-    let registry = this._registry;
-
-    return this._first.then(() = {
-      return Promise.all(promises);
-    }).then([saved] => {
-      return Promise.all(saved.map(item => {
-        let args = (item.value as any).data;
-        let command = 'file-operations: open';
-        // Execute the command and if it fails, delete the state restore data.
-        return registry.execute(command, args)
-          .catch(() => { state.remove(item.id); });
-      }));
-    });
-  }
-
   /**
    * Save the layout state for the application.
    */

+ 98 - 0
packages/application/src/mimerenderers.ts

@@ -0,0 +1,98 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  InstanceTracker
+} from '@jupyterlab/apputils';
+
+import {
+  MimeRenderer, MimeRendererFactory
+} from '@jupyterlab/docregistry';
+
+import {
+  IRenderMime
+} from '@jupyterlab/rendermime-interfaces';
+
+import {
+  JupyterLab, JupyterLabPlugin
+} from '.';
+
+import {
+  ILayoutRestorer
+} from './layoutrestorer';
+
+
+/**
+ * Create rendermime plugins for rendermime extension modules.
+ */
+export
+function createRendermimePlugins(extensions: IRenderMime.IExtensionModule[]): JupyterLabPlugin<void>[] {
+  let plugins: JupyterLabPlugin<void>[] = [];
+  extensions.forEach(mod => {
+    let data = mod.default;
+    // Handle commonjs exports.
+    if (!mod.hasOwnProperty('__esModule')) {
+      data = mod as any;
+    }
+    if (!Array.isArray(data)) {
+      data = [data];
+    }
+    data.forEach(item => {
+      let plugin = createRendermimePlugin(item);
+      plugins.push(plugin);
+    });
+  });
+  return plugins;
+}
+
+
+
+/**
+ * Create rendermime plugins for rendermime extension modules.
+ */
+export
+function createRendermimePlugin(item: IRenderMime.IExtension): JupyterLabPlugin<void> {
+  return {
+    id: `jupyter.services.mimerenderer-${item.mimeType}`,
+    requires: [ILayoutRestorer],
+    autoStart: true,
+    activate: (app: JupyterLab, restorer: ILayoutRestorer) => {
+      // Add the mime renderer.
+      app.rendermime.addRenderer({
+        mimeType: item.mimeType,
+        renderer: item.renderer
+      }, item.rendererIndex || 0);
+
+      // Handle the widget factory.
+      if (!item.widgetFactoryOptions) {
+        return;
+      }
+
+      let factory = new MimeRendererFactory({
+        mimeType: item.mimeType,
+        renderTimeout: item.renderTimeout,
+        dataType: item.dataType,
+        rendermime: app.rendermime,
+        ...item.widgetFactoryOptions,
+      });
+      app.docregistry.addWidgetFactory(factory);
+
+      const factoryName = item.widgetFactoryOptions.name;
+      const namespace = `${factoryName}-renderer`;
+      const tracker = new InstanceTracker<MimeRenderer>({ namespace });
+
+      // Handle state restoration.
+      restorer.restore(tracker, {
+        command: 'file-operations:open',
+        args: widget => ({ path: widget.context.path, factory: factoryName }),
+        name: widget => widget.context.path
+      });
+
+      factory.widgetCreated.connect((sender, widget) => {
+        // Notify the instance tracker if restore data needs to update.
+        widget.context.pathChanged.connect(() => { tracker.save(widget); });
+        tracker.add(widget);
+      });
+    }
+  };
+}

+ 1 - 14
packages/apputils-extension/src/index.ts

@@ -8,8 +8,7 @@ import {
 } from '@jupyterlab/application';
 
 import {
-  CommandLinker, ICommandLinker, ICommandPalette,
-  IMainMenu, MainMenu
+  ICommandPalette, IMainMenu, MainMenu
 } from '@jupyterlab/apputils';
 
 import {
@@ -42,17 +41,6 @@ namespace CommandIDs {
 };
 
 
-/**
- * The default commmand linker provider.
- */
-const linkerPlugin: JupyterLabPlugin<ICommandLinker> = {
-  id: 'jupyter.services.command-linker',
-  provides: ICommandLinker,
-  activate: (app: JupyterLab) => new CommandLinker({ commands: app.commands }),
-  autoStart: true
-};
-
-
 /**
  * A service providing an interface to the main menu.
  */
@@ -138,7 +126,6 @@ const stateDBPlugin: JupyterLabPlugin<IStateDB> = {
  * Export the plugins as default.
  */
 const plugins: JupyterLabPlugin<any>[] = [
-  linkerPlugin,
   mainMenuPlugin,
   palettePlugin,
   settingPlugin,

+ 2 - 2
packages/docregistry/src/default.ts

@@ -288,7 +288,7 @@ class Base64ModelFactory extends TextModelFactory {
  * The default implemetation of a widget factory.
  */
 export
-abstract class ABCWidgetFactory<T extends DocumentRegistry.IDocumentWidget<U>, U extends DocumentRegistry.IModel> implements DocumentRegistry.IWidgetFactory<T, U> {
+abstract class ABCWidgetFactory<T extends DocumentRegistry.IReadyWidget, U extends DocumentRegistry.IModel> implements DocumentRegistry.IWidgetFactory<T, U> {
   /**
    * Construct a new `ABCWidgetFactory`.
    */
@@ -406,7 +406,7 @@ abstract class ABCWidgetFactory<T extends DocumentRegistry.IDocumentWidget<U>, U
  * A widget for rendered mimetype.
  */
 export
-class MimeRenderer extends Widget implements DocumentRegistry.IDocumentWidget<DocumentRegistry.IModel> {
+class MimeRenderer extends Widget implements DocumentRegistry.IReadyWidget {
   /**
    * Construct a new markdown widget.
    */

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

@@ -10,7 +10,7 @@ import {
 } from '@phosphor/algorithm';
 
 import {
-  JSONValue, Token
+  JSONValue
 } from '@phosphor/coreutils';
 
 import {
@@ -42,15 +42,6 @@ import {
 } from '@jupyterlab/rendermime';
 
 
-/* tslint:disable */
-/**
- * The document registry token.
- */
-export
-const IDocumentRegistry = new Token<IDocumentRegistry>('jupyter.services.document-registry');
-/* tslint:enable */
-
-
 /**
  * The interface for a document registry.
  */
@@ -779,18 +770,13 @@ namespace DocumentRegistry {
    * A widget for a document.
    */
   export
-  interface IDocumentWidget<T extends IModel> extends IRenderMime.IReadyWidget {
-    /**
-     * The context associated with the widget.
-     */
-    context: IContext<T>;
-  }
+  interface IReadyWidget extends IRenderMime.IReadyWidget { }
 
   /**
    * The interface for a widget factory.
    */
   export
-  interface IWidgetFactory<T extends IDocumentWidget<U>, U extends IModel> extends IDisposable, IWidgetFactoryOptions {
+  interface IWidgetFactory<T extends IReadyWidget, U extends IModel> extends IDisposable, IWidgetFactoryOptions {
     /**
      * A signal emitted when a widget is created.
      */
@@ -809,7 +795,7 @@ namespace DocumentRegistry {
    * A type alias for a standard widget factory.
    */
   export
-  type WidgetFactory = IWidgetFactory<IDocumentWidget<IModel>, IModel>;
+  type WidgetFactory = IWidgetFactory<IReadyWidget, IModel>;
 
   /**
    * An interface for a widget extension.