浏览代码

Finish refactor of notebook content factories

Steven Silvester 8 年之前
父节点
当前提交
f26f18cb26

+ 2 - 2
src/codeeditor/editor.ts

@@ -684,8 +684,8 @@ namespace CodeEditor {
     readOnly?: boolean;
 
    /**
-     * The default selection style for the editor.
-     */
+    * The default selection style for the editor.
+    */
     selectionStyle?: CodeEditor.ISelectionStyle;
   }
 }

+ 33 - 1
src/codeeditor/widget.ts

@@ -24,7 +24,14 @@ class CodeEditorWidget extends Widget {
    */
   constructor(options: CodeEditorWidget.IOptions) {
     super();
-    this._editor = options.factory({ host: this.node, model: options.model });
+    this._editor = options.factory({
+      host: this.node,
+      model: options.model,
+      uuid: options.uuid,
+      wordWrap: options.wordWrap,
+      readOnly: options.readOnly,
+      selectionStyle: options.selectionStyle
+    });
   }
 
   /**
@@ -175,5 +182,30 @@ namespace CodeEditorWidget {
      * The model used to initialize the code editor.
      */
     model: CodeEditor.IModel;
+
+    /**
+     * The desired uuid for the editor.
+     */
+    uuid?: string;
+
+    /**
+     * Whether line numbers should be displayed. Defaults to `false`.
+     */
+    lineNumbers?: boolean;
+
+    /**
+     * Set to false for horizontal scrolling. Defaults to `true`.
+     */
+    wordWrap?: boolean;
+
+    /**
+     * Whether the editor is read-only. Defaults to `false`.
+     */
+    readOnly?: boolean;
+
+   /**
+    * The default selection style for the editor.
+    */
+    selectionStyle?: CodeEditor.ISelectionStyle;
   }
 }

+ 106 - 48
src/notebook/cells/widget.ts

@@ -124,18 +124,11 @@ class BaseCellWidget extends Widget {
 
     let model = this._model = options.model;
 
-    this._editor = new CodeEditorWidget({
-      model,
-      factory: options.editorFactory
-    });
+    let factory = options.contentFactory;
+    this._editor = factory.createCellEditor(model);
     this._editor.addClass(CELL_EDITOR_CLASS);
 
-    if (options.inputAreaFactory) {
-      this._input = options.inputAreaFactory(this._editor);
-    } else {
-      this._input = new InputAreaWidget(this._editor);
-    }
-
+    this._input = factory.createInputArea(this._editor);
     (this.layout as PanelLayout).addWidget(this._input);
 
     // Handle trusted cursor.
@@ -316,21 +309,85 @@ namespace BaseCellWidget {
     model: ICellModel;
 
     /**
-     * A factory for cell editors.
+     * The factory object for cell components.
+     */
+    contentFactory: BaseCellWidget.IContentFactory;
+  }
+
+  /**
+   * The factory object for cell components.
+   */
+  export
+  interface IContentFactory {
+    /**
+     * The editor factory.
+     */
+    readonly editorFactory: CodeEditor.Factory;
+
+    /**
+     * Create a new cell editor for the widget.
      */
-    editorFactory: CodeEditor.Factory;
+    createCellEditor(model: ICellModel): CodeEditorWidget;
 
     /**
-     * A factory for input areas.
+     * Create a new input area for the widget.
      */
-    inputAreaFactory?: InputAreaFactory;
+    createInputArea(editor: CodeEditorWidget): InputAreaWidget;
   }
 
+
   /**
-   * A factory for input areas.
+   * The default implementation of an `IContentFactory`.
    */
   export
-  type InputAreaFactory = (editor: CodeEditorWidget) => InputAreaWidget;
+  class ContentFactory implements IContentFactory {
+    /**
+     * Creates a new renderer.
+     */
+    constructor(options: ContentFactory.IOptions) {
+      this.editorFactory = options.editorFactory;
+    }
+
+    /**
+     * The editor factory.
+     */
+    readonly editorFactory: CodeEditor.Factory;
+
+    /**
+     * Create a new cell editor for the widget.
+     */
+    createCellEditor(model: CodeEditor.IModel): CodeEditorWidget {
+      return new CodeEditorWidget({
+        factory: this.editorFactory,
+        model,
+        wordWrap: true
+      });
+    }
+
+    /**
+     * Create a new input area for the widget.
+     */
+    createInputArea(editor: CodeEditorWidget): InputAreaWidget {
+      return new InputAreaWidget(editor);
+    }
+  }
+
+  /**
+   * The namespace for the `Renderer` class statics.
+   */
+  export
+  namespace ContentFactory {
+    /**
+     * An options object for initializing a renderer.
+     */
+    export
+    interface IOptions {
+      /**
+       * A code editor factory.
+       */
+      readonly editorFactory: CodeEditor.Factory;
+    }
+  }
 }
 
 
@@ -347,11 +404,8 @@ class CodeCellWidget extends BaseCellWidget {
     this.addClass(CODE_CELL_CLASS);
     this._rendermime = options.rendermime;
 
-    if (options.outputAreaFactory) {
-      this._output = options.outputAreaFactory(this._rendermime);
-    } else {
-      this._output = new OutputAreaWidget(this._rendermime);
-    }
+    let factory = options.contentFactory;
+    this._output = factory.createOutputArea(this._rendermime);
     (this.layout as PanelLayout).addWidget(this._output);
 
     let model = this.model;
@@ -479,26 +533,41 @@ namespace CodeCellWidget {
     rendermime: RenderMime;
 
     /**
-     * A factory for cell editors.
-     */
-    editorFactory: CodeEditor.Factory;
-
-    /**
-     * A factory for input areas.
+     * The factory used to create code cell components.
      */
-    inputAreaFactory?: InputAreaFactory;
+    contentFactory: IContentFactory;
+  }
 
+  /**
+   * A factory for creating code cell widget components.
+   */
+  export
+  interface IContentFactory extends BaseCellWidget.IContentFactory {
     /**
-     * A factory for output areas.
+     * Create a new output area for the widget.
      */
-    outputAreaFactory?: OutputAreaFactory;
+    createOutputArea(rendermime: RenderMime): OutputAreaWidget;
   }
 
   /**
-   * A factory for output areas.
+   * The default implementation of an `IContentFactory`.
    */
   export
-  type OutputAreaFactory = (rendermime: RenderMime) => OutputAreaWidget;
+  class ContentFactory extends BaseCellWidget.ContentFactory implements IContentFactory {
+    /**
+     * Create a new cell editor for the widget.
+     */
+    createCellEditor(model: CodeEditor.IModel): CodeEditorWidget {
+      return new CodeEditorWidget({ factory: this.editorFactory, model });
+    }
+
+    /**
+     * Create an output area widget.
+     */
+    createOutputArea(rendermime: RenderMime): OutputAreaWidget {
+      return new OutputAreaWidget({ rendermime });
+    }
+  }
 }
 
 
@@ -522,7 +591,7 @@ class MarkdownCellWidget extends BaseCellWidget {
     // Insist on the Github-flavored markdown mode.
     this.model.mimeType = 'text/x-ipythongfm';
     this._rendermime = options.rendermime;
-    this._editor.wordWrap = true;
+    this.editor.wordWrap = true;
   }
 
   /**
@@ -624,14 +693,9 @@ namespace MarkdownCellWidget {
     rendermime: RenderMime;
 
     /**
-     * A factory for cell editors.
-     */
-    editorFactory: CodeEditor.Factory;
-
-    /**
-     * A factory for input areas.
+     * The factory object for cell components.
      */
-    inputAreaFactory?: InputAreaFactory;
+    contentFactory: BaseCellWidget.IContentFactory;
   }
 }
 
@@ -647,7 +711,6 @@ class RawCellWidget extends BaseCellWidget {
   constructor(options: BaseCellWidget.IOptions) {
     super(options);
     this.addClass(RAW_CELL_CLASS);
-    this._editor.wordWrap = true;
   }
 
   /**
@@ -673,14 +736,9 @@ namespace RawCellWidget {
     model: IRawCellModel;
 
     /**
-     * A factory for cell editors.
-     */
-    editorFactory: CodeEditor.Factory;
-
-    /**
-     * A factory for input areas.
+     * The factory object for cell components.
      */
-    inputAreaFactory?: InputAreaFactory;
+    contentFactory: BaseCellWidget.IContentFactory;
   }
 }
 

+ 6 - 6
src/notebook/notebook/default-toolbar.ts

@@ -102,7 +102,7 @@ namespace ToolbarItems {
   function createInsertButton(panel: NotebookPanel): ToolbarButton {
     return new ToolbarButton({
       className: TOOLBAR_INSERT_CLASS,
-      onClick: () => { NotebookActions.insertBelow(panel.content); },
+      onClick: () => { NotebookActions.insertBelow(panel.notebook); },
       tooltip: 'Insert a cell below'
     });
   }
@@ -115,7 +115,7 @@ namespace ToolbarItems {
     return new ToolbarButton({
       className: TOOLBAR_CUT_CLASS,
       onClick: () => {
-        NotebookActions.cut(panel.content, panel.clipboard);
+        NotebookActions.cut(panel.notebook, panel.clipboard);
       },
       tooltip: 'Cut the selected cell(s)'
     });
@@ -129,7 +129,7 @@ namespace ToolbarItems {
     return new ToolbarButton({
       className: TOOLBAR_COPY_CLASS,
       onClick: () => {
-        NotebookActions.copy(panel.content, panel.clipboard);
+        NotebookActions.copy(panel.notebook, panel.clipboard);
       },
       tooltip: 'Copy the selected cell(s)'
     });
@@ -143,7 +143,7 @@ namespace ToolbarItems {
     return new ToolbarButton({
       className: TOOLBAR_PASTE_CLASS,
       onClick: () => {
-        NotebookActions.paste(panel.content, panel.clipboard);
+        NotebookActions.paste(panel.notebook, panel.clipboard);
       },
       tooltip: 'Paste cell(s) from the clipboard'
     });
@@ -157,7 +157,7 @@ namespace ToolbarItems {
     return new ToolbarButton({
       className: TOOLBAR_RUN_CLASS,
       onClick: () => {
-        NotebookActions.runAndAdvance(panel.content, panel.kernel);
+        NotebookActions.runAndAdvance(panel.notebook, panel.kernel);
       },
       tooltip: 'Run the selected cell(s) and advance'
     });
@@ -176,7 +176,7 @@ namespace ToolbarItems {
    */
   export
   function createCellTypeItem(panel: NotebookPanel): Widget {
-    return new CellTypeSwitcher(panel.content);
+    return new CellTypeSwitcher(panel.notebook);
   }
 
   /**

+ 67 - 71
src/notebook/notebook/panel.ts

@@ -29,6 +29,10 @@ import {
   Widget
 } from 'phosphor/lib/ui/widget';
 
+import {
+  IEditorMimeTypeService
+} from '../../codeeditor';
+
 import {
   IChangedArgs
 } from '../../common/interfaces';
@@ -84,31 +88,31 @@ class NotebookPanel extends Widget {
   constructor(options: NotebookPanel.IOptions) {
     super();
     this.addClass(NB_PANEL);
-    this._rendermime = options.rendermime;
-    this._clipboard = options.clipboard;
-    this._renderer = options.renderer;
+    this.rendermime = options.rendermime;
+    this.clipboard = options.clipboard;
+    let factory = this.contentFactory = options.contentFactory;
 
     this.layout = new PanelLayout();
-    let rendermime = this._rendermime;
-    this._content = this._renderer.createContent(rendermime);
-    let toolbar = this._renderer.createToolbar();
+    let rendermime = this.rendermime;
+    this.notebook = factory.createNotebook(rendermime);
+    let toolbar = factory.createToolbar();
 
     let layout = this.layout as PanelLayout;
     layout.addWidget(toolbar);
-    layout.addWidget(this._content);
+    layout.addWidget(this.notebook);
 
-    this._completer = this._renderer.createCompleter();
+    this._completer = factory.createCompleter();
     // The completer widget's anchor node is the node whose scrollTop is
     // pegged to the completer widget's position.
-    this._completer.anchor = this._content.node;
+    this._completer.anchor = this.notebook.node;
     Widget.attach(this._completer, document.body);
 
     // Set up the completer handler.
     this._completerHandler = new CellCompleterHandler({
       completer: this._completer
     });
-    this._completerHandler.activeCell = this._content.activeCell;
-    this._content.activeCellChanged.connect((s, cell) => {
+    this._completerHandler.activeCell = this.notebook.activeCell;
+    this.notebook.activeCellChanged.connect((s, cell) => {
       this._completerHandler.activeCell = cell;
     });
   }
@@ -116,65 +120,57 @@ class NotebookPanel extends Widget {
   /**
    * A signal emitted when the panel has been activated.
    */
-  activated: ISignal<this, void>;
+  readonly activated: ISignal<this, void>;
 
   /**
    * A signal emitted when the panel context changes.
    */
-  contextChanged: ISignal<this, void>;
+  readonly contextChanged: ISignal<this, void>;
 
   /**
    * A signal emitted when the kernel used by the panel changes.
    */
-  kernelChanged: ISignal<this, Kernel.IKernel>;
+  readonly kernelChanged: ISignal<this, Kernel.IKernel>;
 
   /**
-   * Get the toolbar used by the widget.
+   * The factory used by the widget.
    */
-  get toolbar(): Toolbar<Widget> {
-    return (this.layout as PanelLayout).widgets.at(0) as Toolbar<Widget>;
-  }
+  readonly contentFactory: NotebookPanel.IContentFactory;
 
   /**
-   * Get the content area used by the widget.
+   * The Rendermime instance used by the widget.
    */
-  get content(): Notebook {
-    return this._content;
-  }
+  readonly rendermime: RenderMime;
 
   /**
-   * Get the current kernel used by the panel.
+   * The clipboard instance used by the widget.
    */
-  get kernel(): Kernel.IKernel {
-    return this._context ? this._context.kernel : null;
-  }
+  readonly clipboard: IClipboard;
 
   /**
-   * Get the rendermime instance used by the widget.
+   * The notebook used by the widget.
    */
-  get rendermime(): RenderMime {
-    return this._rendermime;
-  }
+  readonly notebook: Notebook;
 
   /**
-   * Get the renderer used by the widget.
+   * Get the toolbar used by the widget.
    */
-  get renderer(): NotebookPanel.IRenderer {
-    return this._renderer;
+  get toolbar(): Toolbar<Widget> {
+    return (this.layout as PanelLayout).widgets.at(0) as Toolbar<Widget>;
   }
 
   /**
-   * Get the clipboard instance used by the widget.
+   * Get the current kernel used by the panel.
    */
-  get clipboard(): IClipboard {
-    return this._clipboard;
+  get kernel(): Kernel.IKernel {
+    return this._context ? this._context.kernel : null;
   }
 
   /**
    * The model for the widget.
    */
   get model(): INotebookModel {
-    return this._content ? this._content.model : null;
+    return this.notebook ? this.notebook.model : null;
   }
 
   /**
@@ -194,7 +190,7 @@ class NotebookPanel extends Widget {
     }
     let oldValue = this._context;
     this._context = newValue;
-    this._rendermime.resolver = newValue;
+    this.rendermime.resolver = newValue;
     // Trigger private, protected, and public changes.
     this._onContextChanged(oldValue, newValue);
     this.onContextChanged(oldValue, newValue);
@@ -209,15 +205,11 @@ class NotebookPanel extends Widget {
       return;
     }
     this._context = null;
-    this._content.dispose();
-    this._content = null;
-    this._rendermime = null;
-    this._clipboard = null;
+    this.notebook.dispose();
     this._completerHandler.dispose();
     this._completerHandler = null;
     this._completer.dispose();
     this._completer = null;
-    this._renderer = null;
     super.dispose();
   }
 
@@ -225,7 +217,7 @@ class NotebookPanel extends Widget {
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    this.content.activate();
+    this.notebook.activate();
     this.activated.emit(void 0);
   }
 
@@ -277,7 +269,7 @@ class NotebookPanel extends Widget {
     if (context.kernel !== oldKernel) {
       this._onKernelChanged(this._context, this._context.kernel);
     }
-    this._content.model = newValue.model;
+    this.notebook.model = newValue.model;
     this._handleDirtyState();
     newValue.model.stateChanged.connect(this.onModelStateChanged, this);
 
@@ -302,7 +294,7 @@ class NotebookPanel extends Widget {
    */
   private _onKernelChanged(context: DocumentRegistry.IContext<INotebookModel>, kernel: Kernel.IKernel): void {
     this._completerHandler.kernel = kernel;
-    this.content.inspectionHandler.kernel = kernel;
+    this.notebook.inspectionHandler.kernel = kernel;
     this.kernelChanged.emit(kernel);
     if (!this.model || !kernel) {
       return;
@@ -351,13 +343,9 @@ class NotebookPanel extends Widget {
     }
   }
 
-  private _clipboard: IClipboard = null;
   private _completer: CompleterWidget = null;
   private _completerHandler: CellCompleterHandler = null;
-  private _content: Notebook = null;
   private _context: DocumentRegistry.IContext<INotebookModel> = null;
-  private _renderer: NotebookPanel.IRenderer = null;
-  private _rendermime: RenderMime = null;
 }
 
 
@@ -387,22 +375,20 @@ export namespace NotebookPanel {
     clipboard: IClipboard;
 
     /**
-     * The content renderer for the panel.
-     *
-     * The default is a shared `IRenderer` instance.
+     * The content factory for the panel.
      */
-    renderer: IRenderer;
+    contentFactory: IContentFactory;
   }
 
   /**
-   * A renderer interface for NotebookPanels.
+   * A content factory interface for NotebookPanel.
    */
   export
-  interface IRenderer {
+  interface IContentFactory {
     /**
      * Create a new content area for the panel.
      */
-    createContent(rendermime: RenderMime): Notebook;
+    createNotebook(rendermime: RenderMime): Notebook;
 
     /**
      * Create a new toolbar for the panel.
@@ -416,30 +402,35 @@ export namespace NotebookPanel {
   }
 
   /**
-   * The default implementation of an `IRenderer`.
+   * The default implementation of an `IContentFactory`.
    */
   export
-  class Renderer implements IRenderer {
+  class ContentFactory implements IContentFactory {
+    /**
+     * The notebook content factory.
+     */
+    readonly notebookContentFactory: Notebook.IContentFactory;
 
     /**
-     * The notebook renderer.
+     * The mimeType service.
      */
-    readonly notebookRenderer: Notebook.Renderer;
+    readonly mimeTypeService: IEditorMimeTypeService;
 
     /**
      * Creates a new renderer.
      */
-    constructor(options: Renderer.IOptions) {
-      this.notebookRenderer = options.notebookRenderer;
+    constructor(options: ContentFactory.IOptions) {
+      this.notebookContentFactory = options.notebookContentFactory;
     }
 
     /**
      * Create a new content area for the panel.
      */
-    createContent(rendermime: RenderMime): Notebook {
+    createNotebook(rendermime: RenderMime): Notebook {
       return new Notebook({
         rendermime,
-        renderer: this.notebookRenderer
+        contentFactory: this.notebookContentFactory,
+        mimeTypeService: this.mimeTypeService
       });
     }
 
@@ -459,19 +450,24 @@ export namespace NotebookPanel {
   }
 
   /**
-   * The namespace for `Renderer`.
+   * The namespace for `ContentFactory`.
    */
   export
-  namespace Renderer {
+  namespace ContentFactory {
     /**
-     * An initialization options for a notebook panel renderer.
+     * An initialization options for a notebook panel factory.
      */
     export
     interface IOptions {
       /**
-       * The notebook renderer.
+       * The notebook content factory.
+       */
+      readonly notebookContentFactory: Notebook.IContentFactory;
+
+      /**
+       * The mimeType service.
        */
-      readonly notebookRenderer: Notebook.Renderer;
+      readonly mimeTypeService: IEditorMimeTypeService;
     }
   }
 
@@ -480,6 +476,6 @@ export namespace NotebookPanel {
    * The notebook renderer token.
    */
   export
-  const IRenderer = new Token<IRenderer>('jupyter.services.notebook.renderer');
+  const IContentFactory = new Token<IContentFactory>('jupyter.services.notebook.factory');
   /* tslint:enable */
 }

+ 84 - 59
src/notebook/notebook/widget.ts

@@ -70,7 +70,7 @@ import {
 } from '../../rendermime';
 
 import {
-  IEditorMimeTypeService, IEditorServices, CodeEditor
+  IEditorMimeTypeService, CodeEditor
 } from '../../codeeditor';
 
 import {
@@ -180,15 +180,16 @@ class StaticNotebook extends Widget {
   constructor(options: StaticNotebook.IOptions) {
     super();
     this.addClass(NB_CLASS);
-    this._rendermime = options.rendermime;
+    this.rendermime = options.rendermime;
     this.layout = new Private.NotebookPanelLayout();
-    this._renderer = options.renderer;
+    this.contentFactory = options.contentFactory;
+    this._mimetypeService = options.mimeTypeService;
   }
 
   /**
    * A signal emitted when the model of the notebook changes.
    */
-  modelChanged: ISignal<this, void>;
+  readonly modelChanged: ISignal<this, void>;
 
   /**
    * A signal emitted when the model content changes.
@@ -196,7 +197,17 @@ class StaticNotebook extends Widget {
    * #### Notes
    * This is a convenience signal that follows the current model.
    */
-  modelContentChanged: ISignal<this, void>;
+  readonly modelContentChanged: ISignal<this, void>;
+
+  /**
+   * The cell factory used by the widget.
+   */
+  readonly contentFactory: StaticNotebook.IContentFactory;
+
+  /**
+   * The Rendermime instance used by the widget.
+   */
+  readonly rendermime: RenderMime;
 
   /**
    * The model for the widget.
@@ -217,20 +228,6 @@ class StaticNotebook extends Widget {
     this.modelChanged.emit(void 0);
   }
 
-  /**
-   * Get the rendermime instance used by the widget.
-   */
-  get rendermime(): RenderMime {
-    return this._rendermime;
-  }
-
-  /**
-   * Get the renderer used by the widget.
-   */
-  get renderer(): StaticNotebook.IRenderer {
-    return this._renderer;
-  }
-
   /**
    * Get the mimetype for code cells.
    */
@@ -254,8 +251,6 @@ class StaticNotebook extends Widget {
       return;
     }
     this._model = null;
-    this._rendermime = null;
-    this._renderer = null;
     super.dispose();
   }
 
@@ -392,15 +387,17 @@ class StaticNotebook extends Widget {
    */
   private _insertCell(index: number, cell: ICellModel): void {
     let widget: BaseCellWidget;
+    let factory = this.contentFactory;
+    let rendermime = this.rendermime;
     switch (cell.type) {
     case 'code':
-      widget = this._renderer.createCodeCell(cell as CodeCellModel, this._rendermime);
+      widget = factory.createCodeCell(cell as CodeCellModel, rendermime);
       break;
     case 'markdown':
-      widget = this._renderer.createMarkdownCell(cell as MarkdownCellModel, this._rendermime);
+      widget = factory.createMarkdownCell(cell as MarkdownCellModel, rendermime);
       break;
     default:
-      widget = this._renderer.createRawCell(cell as RawCellModel);
+      widget = factory.createRawCell(cell as RawCellModel);
     }
     widget.addClass(NB_CELL_CLASS);
     let layout = this.layout as PanelLayout;
@@ -435,7 +432,7 @@ class StaticNotebook extends Widget {
   private _updateMimetype(): void {
     let cursor = this._model.getMetadata('language_info');
     let info = cursor.getValue() as nbformat.ILanguageInfoMetadata;
-    this._mimetype = this._renderer.getCodeMimetype(info);
+    this._mimetype = this._mimetypeService.getMimeTypeByLanguage(info);
     each(this.widgets, widget => {
       widget.model.mimeType = this._mimetype;
     });
@@ -443,8 +440,7 @@ class StaticNotebook extends Widget {
 
   private _mimetype = 'text/plain';
   private _model: INotebookModel = null;
-  private _rendermime: RenderMime = null;
-  private _renderer: StaticNotebook.IRenderer = null;
+  private _mimetypeService: IEditorMimeTypeService;
 }
 
 
@@ -474,9 +470,9 @@ namespace StaticNotebook {
     languagePreference?: string;
 
     /**
-     * A factory for creating cells.
+     * A factory for creating content.
      */
-    cellFactory: ICellFactory;
+    contentFactory: IContentFactory;
 
     /**
      * The service used to look up mime types.
@@ -485,10 +481,10 @@ namespace StaticNotebook {
   }
 
   /**
-   * A factory for creating code cell widgets.
+   * A factory for creating notebook content.
    */
   export
-  interface ICellFactory {
+  interface IContentFactory {
     /**
      * Create a new code cell widget.
      */
@@ -506,19 +502,46 @@ namespace StaticNotebook {
   }
 
   /**
-   * The default implementation of an `IFactory`.
+   * The default implementation of an `IContentFactory`.
    */
   export
-  class CellFactory implements ICellFactory {
+  class ContentFactory implements IContentFactory {
     /**
      * Creates a new renderer.
      */
-    constructor(options: CodeCellWidget.IOptions) {
-      this._editorFactory = options.editorFactory;
-      this._inputAreaFactory = options.inputAreaFactory;
-      this._outputAreaFactory = options.outputAreaFactory;
+    constructor(options: ContentFactory.IOptions) {
+      let editorFactory = this.editorFactory = options.editorFactory;
+      this.codeContentFactory = (options.codeContentFactory ||
+        new CodeCellWidget.ContentFactory({ editorFactory })
+      );
+      this.markdownContentFactory = (options.markdownContentFactory ||
+        new BaseCellWidget.ContentFactory({ editorFactory })
+      );
+      this.rawContentFactory = (options.rawContentFactory ||
+        new BaseCellWidget.ContentFactory({ editorFactory })
+      );
     }
 
+    /**
+     * The editor factory.
+     */
+    readonly editorFactory: CodeEditor.Factory;
+
+    /**
+     * The code cell factory.
+     */
+    readonly codeContentFactory: CodeCellWidget.IContentFactory;
+
+    /**
+     * The markdown cell factory.
+     */
+    readonly markdownContentFactory: BaseCellWidget.IContentFactory;
+
+    /**
+     * The raw cell factory.
+     */
+    readonly rawContentFactory: BaseCellWidget.IContentFactory;
+
     /**
      * Create a new code cell widget.
      */
@@ -526,9 +549,7 @@ namespace StaticNotebook {
       return new CodeCellWidget({
         model,
         rendermime,
-        editorFactory: this._editorFactory,
-        inputAreaFactory: this._inputAreaFactory,
-        outputAreaFactory: this._outputAreaFactory
+        contentFactory: this.codeContentFactory
       });
     }
 
@@ -539,8 +560,7 @@ namespace StaticNotebook {
       return new MarkdownCellWidget({
         model,
         rendermime,
-        editorFactory: this._editorFactory,
-        inputAreaFactory: this._inputAreaFactory
+        contentFactory: this.markdownContentFactory
       });
     }
 
@@ -550,22 +570,16 @@ namespace StaticNotebook {
     createRawCell(model: IRawCellModel): RawCellWidget {
       return new RawCellWidget({
         model,
-        rendermime,
-        editorFactory: this._editorFactory,
-        inputAreaFactory: this._inputAreaFactory
+        contentFactory: this.rawContentFactory
       });
     }
-
-    private _editorFactory: CodeEditor.Factory = null;
-    private _inputAreaFactory: BaseCellWidget.InputAreaFactory | null = null;
-    private _outputAreaFactory: BaseCellWidget.OutputAreaFactory | null = null;
   }
 
   /**
    * The namespace for the `Renderer` class statics.
    */
   export
-  namespace CellFactory {
+  namespace ContentFactory {
     /**
      * An options object for initializing a notebook renderer.
      */
@@ -577,14 +591,19 @@ namespace StaticNotebook {
       editorFactory: CodeEditor.Factory;
 
       /**
-       * A factory for input areas.
+       * A factory for code cells.
        */
-      inputAreaFactory?: InputAreaFactory;
+      codeContentFactory?: CodeCellWidget.IContentFactory;
 
       /**
-       * A factory for output areas.
+       * A factory for markdown cells.
        */
-      outputAreaFactory?: OutputAreaFactory;
+      markdownContentFactory?: BaseCellWidget.IContentFactory;
+
+      /**
+       * A factory for raw cells.
+       */
+      rawContentFactory?: BaseCellWidget.IContentFactory;
     }
   }
 }
@@ -618,17 +637,17 @@ class Notebook extends StaticNotebook {
    * This can be due to the active index changing or the
    * cell at the active index changing.
    */
-  activeCellChanged: ISignal<this, BaseCellWidget>;
+  readonly activeCellChanged: ISignal<this, BaseCellWidget>;
 
   /**
    * A signal emitted when the state of the notebook changes.
    */
-  stateChanged: ISignal<this, IChangedArgs<any>>;
+  readonly stateChanged: ISignal<this, IChangedArgs<any>>;
 
   /**
    * A signal emitted when the selection state of the notebook changes.
    */
-  selectionChanged: ISignal<this, void>;
+  readonly selectionChanged: ISignal<this, void>;
 
   /**
    * Get the inspection handler used by the console.
@@ -1373,10 +1392,16 @@ namespace Notebook {
   interface IOptions extends StaticNotebook.IOptions { }
 
   /**
-   * The default implementation of an `IRenderer`.
+   * The cell factory for the notebook
+   */
+  export
+  interface IContentFactory extends StaticNotebook.IContentFactory { }
+
+  /**
+   * The default implementation of an `IFactory`.
    */
   export
-  class Renderer extends StaticNotebook.Renderer { }
+  class ContentFactory extends StaticNotebook.ContentFactory { }
 
 }
 

+ 32 - 18
src/notebook/notebook/widgetfactory.ts

@@ -1,14 +1,14 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import {
-  Kernel
-} from '@jupyterlab/services';
-
 import {
   MimeData as IClipboard
 } from 'phosphor/lib/core/mimedata';
 
+import {
+  IEditorMimeTypeService
+} from '../../codeeditor';
+
 import {
   ABCWidgetFactory, DocumentRegistry
 } from '../../docregistry';
@@ -42,11 +42,31 @@ class NotebookWidgetFactory extends ABCWidgetFactory<NotebookPanel, INotebookMod
    */
   constructor(options: NotebookWidgetFactory.IOptions) {
     super(options);
-    this._rendermime = options.rendermime;
-    this._clipboard = options.clipboard;
-    this._renderer = options.renderer;
+    this.rendermime = options.rendermime;
+    this.clipboard = options.clipboard;
+    this.contentFactory = options.contentFactory;
   }
 
+  /*
+   * The rendermime instance.
+   */
+  readonly rendermime: RenderMime;
+
+  /**
+   * The content factory used by the widget factory.
+   */
+  readonly contentFactory: NotebookPanel.IContentFactory;
+
+  /**
+   * A clipboard instance.
+   */
+  readonly clipboard: IClipboard;
+
+  /**
+   * The service used to look up mime types.
+   */
+  readonly mimeTypeService: IEditorMimeTypeService;
+
   /**
    * Dispose of the resources used by the factory.
    */
@@ -54,8 +74,6 @@ class NotebookWidgetFactory extends ABCWidgetFactory<NotebookPanel, INotebookMod
     if (this.isDisposed) {
       return;
     }
-    this._rendermime = null;
-    this._clipboard = null;
     super.dispose();
   }
 
@@ -67,20 +85,16 @@ class NotebookWidgetFactory extends ABCWidgetFactory<NotebookPanel, INotebookMod
    * the default toolbar items using `ToolbarItems.populateDefaults`.
    */
   protected createNewWidget(context: DocumentRegistry.IContext<INotebookModel>): NotebookPanel {
-    let rendermime = this._rendermime.clone();
+    let rendermime = this.rendermime.clone();
     let panel = new NotebookPanel({
       rendermime,
-      clipboard: this._clipboard,
-      renderer: this._renderer
+      clipboard: this.clipboard,
+      contentFactory: this.contentFactory
     });
     panel.context = context;
     ToolbarItems.populateDefaults(panel);
     return panel;
   }
-
-  private _rendermime: RenderMime = null;
-  private _clipboard: IClipboard = null;
-  private _renderer: NotebookPanel.IRenderer = null;
 }
 
 
@@ -105,8 +119,8 @@ namespace NotebookWidgetFactory {
     clipboard: IClipboard;
 
     /**
-     * A notebook panel renderer.
+     * A notebook panel content factory.
      */
-    renderer: NotebookPanel.IRenderer;
+    contentFactory: NotebookPanel.IContentFactory;
   }
 }

+ 51 - 47
src/notebook/plugin.ts

@@ -131,7 +131,7 @@ const trackerPlugin: JupyterLabPlugin<INotebookTracker> = {
     IMainMenu,
     ICommandPalette,
     IInspector,
-    NotebookPanel.IRenderer,
+    NotebookPanel.IContentFactory,
     IInstanceRestorer
   ],
   activate: activateNotebookHandler,
@@ -140,17 +140,21 @@ const trackerPlugin: JupyterLabPlugin<INotebookTracker> = {
 
 
 /**
- * The notebook renderer provider.
+ * The notebook cell factory provider.
  */
 export
-const rendererPlugin: JupyterLabPlugin<NotebookPanel.IRenderer> = {
+const rendererPlugin: JupyterLabPlugin<NotebookPanel.IContentFactory> = {
   id: 'jupyter.services.notebook-renderer',
-  provides: NotebookPanel.IRenderer,
+  provides: NotebookPanel.IContentFactory,
   requires: [IEditorServices],
   autoStart: true,
   activate: (app: JupyterLab, editorServices: IEditorServices) => {
-    const notebookRenderer = new Notebook.Renderer({ editorServices });
-    return new NotebookPanel.Renderer({ notebookRenderer });
+    let editorFactory = editorServices.factoryService.newInlineEditor;
+    const nbFactory = new Notebook.ContentFactory({ editorFactory });
+    return new NotebookPanel.ContentFactory({
+      notebookContentFactory: nbFactory,
+      mimeTypeService: editorServices.mimeTypeService
+    });
   }
 };
 
@@ -165,7 +169,7 @@ export default plugins;
 /**
  * Activate the notebook handler extension.
  */
-function activateNotebookHandler(app: JupyterLab, registry: IDocumentRegistry, services: IServiceManager, rendermime: IRenderMime, clipboard: IClipboard, mainMenu: IMainMenu, palette: ICommandPalette, inspector: IInspector, renderer: NotebookPanel.IRenderer, restorer: IInstanceRestorer): INotebookTracker {
+function activateNotebookHandler(app: JupyterLab, registry: IDocumentRegistry, services: IServiceManager, rendermime: IRenderMime, clipboard: IClipboard, mainMenu: IMainMenu, palette: ICommandPalette, inspector: IInspector, contentFactory: NotebookPanel.IContentFactory, restorer: IInstanceRestorer): INotebookTracker {
 
   const factory = new NotebookWidgetFactory({
     name: FACTORY,
@@ -176,7 +180,7 @@ function activateNotebookHandler(app: JupyterLab, registry: IDocumentRegistry, s
     canStartKernel: true,
     rendermime,
     clipboard,
-    renderer
+    contentFactory
   });
 
   const tracker = new NotebookTracker({ namespace: 'notebook' });
@@ -192,7 +196,7 @@ function activateNotebookHandler(app: JupyterLab, registry: IDocumentRegistry, s
   // Set the source of the code inspector.
   tracker.currentChanged.connect((sender, widget) => {
     if (widget) {
-      inspector.source = widget.content.inspectionHandler;
+      inspector.source = widget.notebook.inspectionHandler;
     }
   });
 
@@ -220,7 +224,7 @@ function activateNotebookHandler(app: JupyterLab, registry: IDocumentRegistry, s
     widget.id = widget.id || `notebook-${++id}`;
     widget.title.icon = `${PORTRAIT_ICON_CLASS} ${NOTEBOOK_ICON_CLASS}`;
     // Immediately set the inspector source to the current notebook.
-    inspector.source = widget.content.inspectionHandler;
+    inspector.source = widget.notebook.inspectionHandler;
     // Notify the instance tracker if restore data needs to update.
     widget.context.pathChanged.connect(() => { tracker.save(widget); });
     // Add the notebook panel to the tracker.
@@ -244,7 +248,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        let content = current.content;
+        let content = current.notebook;
         NotebookActions.runAndAdvance(content, current.context.kernel);
       }
     }
@@ -254,7 +258,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.run(current.content, current.context.kernel);
+        NotebookActions.run(current.notebook, current.context.kernel);
       }
     }
   });
@@ -263,7 +267,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.runAndInsert(current.content, current.context.kernel);
+        NotebookActions.runAndInsert(current.notebook, current.context.kernel);
       }
     }
   });
@@ -272,7 +276,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.runAll(current.content, current.context.kernel);
+        NotebookActions.runAll(current.notebook, current.context.kernel);
       }
     }
   });
@@ -316,7 +320,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
         promise.then(result => {
           current.activate();
           if (result) {
-            NotebookActions.clearAllOutputs(current.content);
+            NotebookActions.clearAllOutputs(current.notebook);
           }
         });
       }
@@ -330,7 +334,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
         let promise = restartKernel(current.kernel, current.node);
         promise.then(result => {
           current.activate();
-          NotebookActions.runAll(current.content, current.context.kernel);
+          NotebookActions.runAll(current.notebook, current.context.kernel);
         });
       }
     }
@@ -340,7 +344,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.clearAllOutputs(current.content);
+        NotebookActions.clearAllOutputs(current.notebook);
       }
     }
   });
@@ -349,7 +353,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.clearOutputs(current.content);
+        NotebookActions.clearOutputs(current.notebook);
       }
     }
   });
@@ -370,7 +374,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.changeCellType(current.content, 'code');
+        NotebookActions.changeCellType(current.notebook, 'code');
       }
     }
   });
@@ -379,7 +383,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.changeCellType(current.content, 'markdown');
+        NotebookActions.changeCellType(current.notebook, 'markdown');
       }
     }
   });
@@ -388,7 +392,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.changeCellType(current.content, 'raw');
+        NotebookActions.changeCellType(current.notebook, 'raw');
       }
     }
   });
@@ -397,7 +401,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.cut(current.content, current.clipboard);
+        NotebookActions.cut(current.notebook, current.clipboard);
       }
     }
   });
@@ -406,7 +410,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.copy(current.content, current.clipboard);
+        NotebookActions.copy(current.notebook, current.clipboard);
       }
     }
   });
@@ -415,7 +419,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.paste(current.content, current.clipboard);
+        NotebookActions.paste(current.notebook, current.clipboard);
       }
     }
   });
@@ -424,7 +428,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.deleteCells(current.content);
+        NotebookActions.deleteCells(current.notebook);
       }
     }
   });
@@ -433,7 +437,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.splitCell(current.content);
+        NotebookActions.splitCell(current.notebook);
       }
     }
   });
@@ -442,7 +446,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.mergeCells(current.content);
+        NotebookActions.mergeCells(current.notebook);
       }
     }
   });
@@ -451,7 +455,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.insertAbove(current.content);
+        NotebookActions.insertAbove(current.notebook);
       }
     }
   });
@@ -460,7 +464,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.insertBelow(current.content);
+        NotebookActions.insertBelow(current.notebook);
       }
     }
   });
@@ -469,7 +473,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.selectAbove(current.content);
+        NotebookActions.selectAbove(current.notebook);
       }
     }
   });
@@ -478,7 +482,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.selectBelow(current.content);
+        NotebookActions.selectBelow(current.notebook);
       }
     }
   });
@@ -487,7 +491,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.extendSelectionAbove(current.content);
+        NotebookActions.extendSelectionAbove(current.notebook);
       }
     }
   });
@@ -496,7 +500,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.extendSelectionBelow(current.content);
+        NotebookActions.extendSelectionBelow(current.notebook);
       }
     }
   });
@@ -505,7 +509,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.moveUp(current.content);
+        NotebookActions.moveUp(current.notebook);
       }
     }
   });
@@ -514,7 +518,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.moveDown(current.content);
+        NotebookActions.moveDown(current.notebook);
       }
     }
   });
@@ -523,7 +527,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.toggleLineNumbers(current.content);
+        NotebookActions.toggleLineNumbers(current.notebook);
       }
     }
   });
@@ -532,7 +536,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.toggleAllLineNumbers(current.content);
+        NotebookActions.toggleAllLineNumbers(current.notebook);
       }
     }
   });
@@ -541,7 +545,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        current.content.mode = 'command';
+        current.notebook.mode = 'command';
       }
     }
   });
@@ -550,7 +554,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        current.content.mode = 'edit';
+        current.notebook.mode = 'edit';
       }
     }
   });
@@ -559,7 +563,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.undo(current.content);
+        NotebookActions.undo(current.notebook);
       }
     }
   });
@@ -568,7 +572,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.redo(current.content);
+        NotebookActions.redo(current.notebook);
       }
     }
   });
@@ -590,7 +594,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 1);
+        NotebookActions.setMarkdownHeader(current.notebook, 1);
       }
     }
   });
@@ -599,7 +603,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 2);
+        NotebookActions.setMarkdownHeader(current.notebook, 2);
       }
     }
   });
@@ -608,7 +612,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 3);
+        NotebookActions.setMarkdownHeader(current.notebook, 3);
       }
     }
   });
@@ -617,7 +621,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 4);
+        NotebookActions.setMarkdownHeader(current.notebook, 4);
       }
     }
   });
@@ -626,7 +630,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 5);
+        NotebookActions.setMarkdownHeader(current.notebook, 5);
       }
     }
   });
@@ -635,7 +639,7 @@ function addCommands(app: JupyterLab, services: IServiceManager, tracker: Notebo
     execute: () => {
       let current = tracker.currentWidget;
       if (current) {
-        NotebookActions.setMarkdownHeader(current.content, 6);
+        NotebookActions.setMarkdownHeader(current.notebook, 6);
       }
     }
   });

+ 2 - 2
src/notebook/tracker.ts

@@ -68,7 +68,7 @@ class NotebookTracker extends InstanceTracker<NotebookPanel> implements INoteboo
     if (!widget) {
       return null;
     }
-    return widget.content.activeCell || null;
+    return widget.notebook.activeCell || null;
   }
 
   /**
@@ -118,7 +118,7 @@ class NotebookTracker extends InstanceTracker<NotebookPanel> implements INoteboo
     }
 
     // Since the notebook has changed, immediately signal an active cell change.
-    this.activeCellChanged.emit(widget.content.activeCell || null);
+    this.activeCellChanged.emit(widget.notebook.activeCell || null);
   }
 
   private _onActiveCellChanged(sender: Notebook, cell: BaseCellWidget): void {