Pārlūkot izejas kodu

Update jupyter-js-services and clean up interfaces

Steven Silvester 8 gadi atpakaļ
vecāks
revīzija
80cbeb2242

+ 1 - 1
examples/console/package.json

@@ -9,7 +9,7 @@
     "watch": "watch 'npm run update && npm run build' ../../src src --wait 10"
   },
   "dependencies": {
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../..",
     "phosphor-commandpalette": "^0.2.0",
     "phosphor-keymap": "^0.8.0",

+ 1 - 1
examples/filebrowser/package.json

@@ -9,7 +9,7 @@
     "watch": "watch 'npm run update && npm run build' ../../src src --wait 10"
   },
   "dependencies": {
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../..",
     "phosphor-dockpanel": "^0.9.7",
     "phosphor-keymap": "^0.8.0",

+ 1 - 1
examples/lab/package.json

@@ -10,7 +10,7 @@
   },
   "dependencies": {
     "es6-promise": "^3.1.2",
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../../",
     "phosphide": "^0.9.5"
   },

+ 1 - 1
examples/notebook/package.json

@@ -9,7 +9,7 @@
     "watch": "watch 'npm run update && npm run build' ../../src src --wait 10"
   },
   "dependencies": {
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../..",
     "phosphor-commandpalette": "^0.2.0",
     "phosphor-dragdrop": "^0.9.1",

+ 1 - 1
examples/terminal/package.json

@@ -9,7 +9,7 @@
     "watch": "watch 'npm run update && npm run build' ../../src src --wait 10"
   },
   "dependencies": {
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../..",
     "phosphor-dockpanel": "^0.9.7"
   },

+ 1 - 1
jupyterlab/package.json

@@ -8,7 +8,7 @@
   "dependencies": {
     "es6-promise": "^3.1.2",
     "font-awesome": "^4.6.1",
-    "jupyter-js-services": "^0.11.1",
+    "jupyter-js-services": "^0.12.1",
     "jupyterlab": "file:../",
     "phosphide": "^0.9.5"
   },

+ 1 - 1
package.json

@@ -13,7 +13,7 @@
     "file-loader": "^0.8.5",
     "jquery": "^2.2.0",
     "jquery-ui": "^1.10.5",
-    "jupyter-js-services": "^0.11.3",
+    "jupyter-js-services": "^0.12.1",
     "jupyter-js-utils": "^0.4.0",
     "jupyter-js-widgets": "2.0.0-dev.0",
     "marked": "^0.3.5",

+ 23 - 19
src/docmanager/context.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsManager, IContentsModel, IContentsOpts, IKernel, ISession
+  IContents, IKernel, ISession
 } from 'jupyter-js-services';
 
 import * as utils
@@ -54,7 +54,7 @@ class Context implements IDocumentContext<IDocumentModel> {
   /**
    * A signal emitted when the model is saved or reverted.
    */
-  get contentsModelChanged(): ISignal<Context, IContentsModel> {
+  get contentsModelChanged(): ISignal<Context, IContents.IModel> {
     return Private.contentsModelChangedSignal.bind(this);
   }
 
@@ -112,7 +112,7 @@ class Context implements IDocumentContext<IDocumentModel> {
    * This is a read-only property.  The model will have an
    * empty `contents` field.
    */
-  get contentsModel(): IContentsModel {
+  get contentsModel(): IContents.IModel {
     return this._manager.getContentsModel(this._id);
   }
 
@@ -265,7 +265,8 @@ class ContextManager implements IDisposable {
       path,
       model,
       modelName: factory.name,
-      opts: factory.contentsOptions,
+      fileType: factory.fileType,
+      fileFormat: factory.fileFormat,
       contentsModel: null,
       session: null,
       isPopulated: false
@@ -340,7 +341,7 @@ class ContextManager implements IDisposable {
   /**
    * Get the current contents model associated with a document.
    */
-  getContentsModel(id: string): IContentsModel {
+  getContentsModel(id: string): IContents.IModel {
     return this._contexts[id].contentsModel;
   }
 
@@ -417,19 +418,21 @@ class ContextManager implements IDisposable {
    */
   save(id: string): Promise<void> {
     let contextEx =  this._contexts[id];
-    let opts = utils.copy(contextEx.opts);
-    let path = contextEx.path;
     let model = contextEx.model;
+    let contents = contextEx.contentsModel || {};
+    let path = contextEx.path;
+    contents.type = contextEx.fileType;
+    contents.format = contextEx.fileFormat;
     if (model.readOnly) {
       return Promise.reject(new Error('Read only'));
     }
-    if (opts.type === 'notebook' || opts.format === 'json') {
-      opts.content = model.toJSON();
+    if (contents.format === 'json') {
+      contents.content = model.toJSON();
     } else {
-      opts.content = model.toString();
+      contents.content = model.toString();
     }
-    return this._contentsManager.save(path, opts).then(contents => {
-      contextEx.contentsModel = this._copyContentsModel(contents);
+    return this._contentsManager.save(path, contents).then(newContents => {
+      contextEx.contentsModel = this._copyContentsModel(newContents);
       model.dirty = false;
     });
   }
@@ -460,7 +463,7 @@ class ContextManager implements IDisposable {
    */
   revert(id: string): Promise<void> {
     let contextEx = this._contexts[id];
-    let opts = contextEx.opts;
+    let opts = { format: contextEx.fileFormat, type: contextEx.fileType };
     let path = contextEx.path;
     let model = contextEx.model;
     return this._contentsManager.get(path, opts).then(contents => {
@@ -540,7 +543,7 @@ class ContextManager implements IDisposable {
   /**
    * Copy the contents of a contents model, without the content.
    */
-  private _copyContentsModel(model: IContentsModel): IContentsModel {
+  private _copyContentsModel(model: IContents.IModel): IContents.IModel {
     return {
       path: model.path,
       name: model.name,
@@ -553,7 +556,7 @@ class ContextManager implements IDisposable {
     };
   }
 
-  private _contentsManager: IContentsManager = null;
+  private _contentsManager: IContents.IManager = null;
   private _sessionManager: ISession.IManager = null;
   private _kernelspecids: IKernel.ISpecModels = null;
   private _contexts: { [key: string]: Private.IContextEx } = Object.create(null);
@@ -573,7 +576,7 @@ export namespace ContextManager {
     /**
      * A contents manager instance.
      */
-    contentsManager: IContentsManager;
+    contentsManager: IContents.IManager;
 
     /**
      * A session manager instance.
@@ -605,9 +608,10 @@ namespace Private {
     context: IDocumentContext<IDocumentModel>;
     model: IDocumentModel;
     session: ISession;
-    opts: IContentsOpts;
+    fileType: IContents.FileType;
+    fileFormat: IContents.FileFormat;
     path: string;
-    contentsModel: IContentsModel;
+    contentsModel: IContents.IModel;
     modelName: string;
     isPopulated: boolean;
   }
@@ -628,7 +632,7 @@ namespace Private {
    * A signal emitted when the contentsModel changes.
    */
   export
-  const contentsModelChangedSignal = new Signal<Context, IContentsModel>();
+  const contentsModelChangedSignal = new Signal<Context, IContents.IModel>();
 
   /**
    * A signal emitted when the context is fully populated for the first time.

+ 3 - 3
src/docmanager/manager.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsManager, IKernel, ISession
+  IContents, IKernel, ISession
 } from 'jupyter-js-services';
 
 import {
@@ -259,7 +259,7 @@ class DocumentManager implements IDisposable {
     this._widgetManager.closeAll();
   }
 
-  private _contentsManager: IContentsManager = null;
+  private _contentsManager: IContents.IManager = null;
   private _sessionManager: ISession.IManager = null;
   private _contextManager: ContextManager = null;
   private _widgetManager: DocumentWidgetManager = null;
@@ -286,7 +286,7 @@ namespace DocumentManager {
     /**
      * A contents manager instance.
      */
-    contentsManager: IContentsManager;
+    contentsManager: IContents.IManager;
 
     /**
      * A session manager instance.

+ 25 - 7
src/docregistry/default.ts

@@ -5,7 +5,7 @@ import * as CodeMirror
   from 'codemirror';
 
 import {
-  IKernel, IContentsOpts
+  IContents, IKernel
 } from 'jupyter-js-services';
 
 import {
@@ -178,13 +178,22 @@ class TextModelFactory implements IModelFactory {
   }
 
   /**
-   * The contents options used to fetch/save files.
+   * The type of the file.
    *
    * #### Notes
    * This is a read-only property.
    */
-  get contentsOptions(): IContentsOpts {
-    return { type: 'file', format: 'text'};
+  get fileType(): IContents.FileType {
+    return 'file';
+  }
+
+  /**
+   * The format of the file.
+   *
+   * This is a read-only property.
+   */
+  get fileFormat(): IContents.FileFormat {
+    return 'text';
   }
 
   /**
@@ -242,13 +251,22 @@ class Base64ModelFactory extends TextModelFactory {
   }
 
   /**
-   * The contents options used to fetch/save files.
+   * The type of the file.
    *
    * #### Notes
    * This is a read-only property.
    */
-  get contentsOptions(): IContentsOpts {
-    return { type: 'file', format: 'base64'};
+  get fileType(): IContents.FileType {
+    return 'file';
+  }
+
+  /**
+   * The format of the file.
+   *
+   * This is a read-only property.
+   */
+  get fileFormat(): IContents.FileFormat {
+    return 'base64';
   }
 }
 

+ 25 - 13
src/docregistry/interfaces.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsModel, IContentsOpts, IKernel, ISession
+  IContents, IKernel, ISession
 } from 'jupyter-js-services';
 
 import {
@@ -112,7 +112,7 @@ export interface IDocumentContext<T extends IDocumentModel> extends IDisposable
   /**
    * A signal emitted when the contentsModel changes.
    */
-  contentsModelChanged: ISignal<IDocumentContext<T>, IContentsModel>;
+  contentsModelChanged: ISignal<IDocumentContext<T>, IContents.IModel>;
 
   /**
    * A signal emitted when the context is fully populated for the first time.
@@ -159,7 +159,7 @@ export interface IDocumentContext<T extends IDocumentModel> extends IDisposable
    * empty `contents` field.  It will be `null` until the
    * first save or load to disk.
    */
-  contentsModel: IContentsModel;
+  contentsModel: IContents.IModel;
 
   /**
    * Get the kernel spec information.
@@ -309,12 +309,19 @@ interface IModelFactory extends IDisposable {
   name: string;
 
   /**
-   * The contents options used to fetch/save files.
+   * The type of the file (defaults to `"file"`).
    *
    * #### Notes
    * This is a read-only property.
    */
-  contentsOptions: IContentsOpts;
+  fileType: IContents.FileType;
+
+  /**
+   * The format of the file (default to `"text"`).
+   *
+   * This is a read-only property.
+   */
+  fileFormat: IContents.FileFormat;
 
   /**
    * Create a new model for a given path.
@@ -378,6 +385,16 @@ interface IFileType {
    * The optional icon class to use for the file type.
    */
   icon?: string;
+
+  /**
+   * The type of the new file (defaults to `"file"`).
+   */
+  fileType?: IContents.FileType;
+
+  /**
+   * The format of the new file (default to `"text"`).
+   */
+  fileFormat?: IContents.FileFormat;
 }
 
 
@@ -387,19 +404,14 @@ interface IFileType {
 export
 interface IFileCreator {
   /**
-   * The display name of the item.
+   * The name of the file creator.
    */
   name: string;
 
   /**
-   * The extension for the new file (e.g. `".txt"`).
-   */
-  extension: string;
-
-  /**
-   * The type of the new file (defaults to `"file"`).
+   * The filetype name associated with the creator.
    */
-  type?: string;
+  fileType: string;
 
   /**
    * The optional widget name.

+ 24 - 0
src/docregistry/registry.ts

@@ -278,6 +278,30 @@ class DocumentRegistry implements IDisposable {
     return this._creators.slice();
   }
 
+  /**
+   * Get a file type by name.
+   */
+  getFileType(name: string): IFileType {
+    for (let i = 0; i < this._fileTypes.length; i++) {
+      let fileType = this._fileTypes[i];
+      if (fileType.name === name) {
+        return fileType;
+      }
+    }
+  }
+
+  /**
+   * Get a creator by name.
+   */
+  getCreator(name: string): IFileCreator {
+    for (let i = 0; i < this._creators.length; i++) {
+      let creator = this._creators[i];
+      if (creator.name === name) {
+        return creator;
+      }
+    }
+  }
+
   /**
    * Get a kernel preference.
    *

+ 6 - 2
src/filebrowser/browser.ts

@@ -1,6 +1,10 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
+import {
+  IContents
+} from 'jupyter-js-services';
+
 import {
   Message
 } from 'phosphor-messaging';
@@ -194,9 +198,9 @@ class FileBrowserWidget extends Widget {
   /**
    * Create a new untitled file in the current directory.
    */
-  createNew(type: string, ext?: string): Promise<Widget> {
+  createNew(options: IContents.ICreateOptions): Promise<Widget> {
     let model = this.model;
-    return model.newUntitled(type, ext).then(contents => {
+    return model.newUntitled(options).then(contents => {
       let widget = this._manager.createNew(contents.path);
       let context = this._manager.contextForWidget(widget);
       context.populated.connect(() => model.refresh() );

+ 14 - 9
src/filebrowser/buttons.ts

@@ -22,7 +22,7 @@ import {
 } from '../docmanager';
 
 import {
-  IFileCreator
+  IFileType
 } from '../docregistry';
 
 import {
@@ -376,14 +376,14 @@ namespace Private {
   /**
    * Create a new item using a file creator.
    */
-  function createNewItem(widget: FileButtons, creator: IFileCreator): void {
-    let fileType = creator.type || 'file';
-    let widgetName = creator.widgetName || 'default';
+  function createNewItem(widget: FileButtons, fileType: IFileType, widgetName: string, kernelName?: string): void {
     let kernel: IKernel.IModel;
-    if (creator.kernelName) {
-      kernel = { name: creator.kernelName };
+    if (kernelName) {
+      kernel = { name: kernelName };
     }
-    widget.model.newUntitled(fileType, creator.extension).then(contents => {
+    widget.model.newUntitled(
+      { type: fileType.fileType, ext: fileType.extension })
+    .then(contents => {
       widget.createNew(contents.path, widgetName, kernel);
     });
   }
@@ -403,14 +403,19 @@ namespace Private {
         handler: () => { createNewFolder(widget); }
       })
     ];
-    let creators = widget.manager.registry.listCreators();
+    let registry = widget.manager.registry;
+    let creators = registry.listCreators();
     if (creators) {
       items.push(new MenuItem({ type: MenuItem.Separator }));
     }
     for (let creator of creators) {
+      let fileType = registry.getFileType(creator.fileType);
       let item = new MenuItem({
         text: creator.name,
-        handler: () => { createNewItem(widget, creator); }
+        handler: () => {
+          let widgetName = creator.widgetName || 'default';
+          let kernelName = creator.kernelName;
+          createNewItem(widget, fileType, widgetName, kernelName); }
       });
       items.push(item);
     }

+ 12 - 12
src/filebrowser/listing.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsModel
+  IContents
 } from 'jupyter-js-services';
 
 import * as moment
@@ -273,7 +273,7 @@ class DirListing extends Widget {
   /**
    * The the sorted content items.
    */
-  get sortedItems(): IContentsModel[] {
+  get sortedItems(): IContents.IModel[] {
     return this._sortedModels;
   }
 
@@ -324,7 +324,7 @@ class DirListing extends Widget {
     if (!this._clipboard.length) {
       return;
     }
-    let promises: Promise<IContentsModel>[] = [];
+    let promises: Promise<IContents.IModel>[] = [];
     for (let path of this._clipboard) {
       if (this._isCut) {
         let parts = path.split('/');
@@ -386,7 +386,7 @@ class DirListing extends Widget {
    * Duplicate the currently selected item(s).
    */
   duplicate(): Promise<void> {
-    let promises: Promise<IContentsModel>[] = [];
+    let promises: Promise<IContents.IModel>[] = [];
     for (let item of this._getSelectedItems()) {
       if (item.type !== 'directory') {
         promises.push(this._model.copy(item.path, this._model.path));
@@ -401,7 +401,7 @@ class DirListing extends Widget {
   /**
    * Download the currently selected item(s).
    */
-  download(): Promise<IContentsModel> {
+  download(): Promise<IContents.IModel> {
     for (let item of this._getSelectedItems()) {
       if (item.type !== 'directory') {
         return this._model.download(item.path).catch(error =>
@@ -913,7 +913,7 @@ class DirListing extends Widget {
     let path = items[index].name + '/';
 
     // Move all of the items.
-    let promises: Promise<IContentsModel>[] = [];
+    let promises: Promise<IContents.IModel>[] = [];
     let names = event.mimeData.getData(utils.CONTENTS_MIME) as string[];
     for (let name of names) {
       let newPath = path + name;
@@ -952,7 +952,7 @@ class DirListing extends Widget {
     let source = this._items[index];
     let model = this._model;
     let items = this.sortedItems;
-    let item: IContentsModel = null;
+    let item: IContents.IModel = null;
 
     // If the source node is not selected, use just that node.
     if (!source.classList.contains(SELECTED_CLASS)) {
@@ -1082,7 +1082,7 @@ class DirListing extends Widget {
   /**
    * Get the currently selected items.
    */
-  private _getSelectedItems(): IContentsModel[] {
+  private _getSelectedItems(): IContents.IModel[] {
     let items = this.sortedItems;
     if (!this._softSelection) {
       return items.filter(item => this._selection[item.name]);
@@ -1212,7 +1212,7 @@ class DirListing extends Widget {
   private _model: FileBrowserModel = null;
   private _editNode: HTMLInputElement = null;
   private _items: HTMLElement[] = [];
-  private _sortedModels: IContentsModel[] = null;
+  private _sortedModels: IContents.IModel[] = null;
   private _sortState: DirListing.ISortState = { direction: 'ascending', key: 'name' };
   private _drag: Drag = null;
   private _dragData: { pressX: number, pressY: number, index: number } = null;
@@ -1315,7 +1315,7 @@ namespace DirListing {
      *
      * @param model - The model object to use for the item state.
      */
-    updateItemNode(node: HTMLElement, model: IContentsModel): void;
+    updateItemNode(node: HTMLElement, model: IContents.IModel): void;
 
     /**
      * Get the node containing the file name.
@@ -1434,7 +1434,7 @@ namespace DirListing {
      *
      * @param model - The model object to use for the item state.
      */
-    updateItemNode(node: HTMLElement, model: IContentsModel): void {
+    updateItemNode(node: HTMLElement, model: IContents.IModel): void {
       let icon = utils.findElement(node, ITEM_ICON_CLASS);
       let text = utils.findElement(node, ITEM_TEXT_CLASS);
       let modified = utils.findElement(node, ITEM_MODIFIED_CLASS);
@@ -1570,7 +1570,7 @@ namespace Private {
    * Sort a list of items by sort state as a new array.
    */
   export
-  function sort(items: IContentsModel[], state: DirListing.ISortState) : IContentsModel[] {
+  function sort(items: IContents.IModel[], state: DirListing.ISortState) : IContents.IModel[] {
     let output = items.slice();
     if (state.key === 'last_modified') {
       output.sort((a, b) => {

+ 26 - 28
src/filebrowser/model.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsManager, IContentsModel, IContentsOpts, IKernel, ISession
+  IContents, IKernel, ISession
 } from 'jupyter-js-services';
 
 import {
@@ -72,7 +72,7 @@ class FileBrowserModel implements IDisposable {
   /**
    * Get a read-only list of the items in the current path.
    */
-  get items(): IContentsModel[] {
+  get items(): IContents.IModel[] {
     return this._model.content ? this._model.content.slice() : [];
   }
 
@@ -121,7 +121,8 @@ class FileBrowserModel implements IDisposable {
       newValue = Private.normalizePath(this._model.path, newValue);
     }
     let oldValue = this.path;
-    return this._contentsManager.get(newValue, {}).then(contents => {
+    let options = { content: true };
+    return this._contentsManager.get(newValue, options).then(contents => {
       this._model = contents;
       return this._findSessions();
     }).then(() => {
@@ -158,7 +159,7 @@ class FileBrowserModel implements IDisposable {
    *
    * @returns A promise which resolves to the contents of the file.
    */
-  copy(fromFile: string, toDir: string): Promise<IContentsModel> {
+  copy(fromFile: string, toDir: string): Promise<IContents.IModel> {
     let normalizePath = Private.normalizePath;
     fromFile = normalizePath(this._model.path, fromFile);
     toDir = normalizePath(this._model.path, toDir);
@@ -198,7 +199,7 @@ class FileBrowserModel implements IDisposable {
    *
    * @returns - A promise which resolves to the file contents.
    */
-  download(path: string): Promise<IContentsModel> {
+  download(path: string): Promise<IContents.IModel> {
     let normalizePath = Private.normalizePath;
     path = normalizePath(this._model.path, path);
     return this._contentsManager.get(path, {}).then(contents => {
@@ -220,15 +221,12 @@ class FileBrowserModel implements IDisposable {
    *
    * @returns A promise containing the new file contents model.
    */
-  newUntitled(type: string, ext?: string): Promise<IContentsModel> {
-    if (type === 'file') {
-      ext = ext || '.txt';
-    } else {
-      ext = '';
+  newUntitled(options: IContents.ICreateOptions): Promise<IContents.IModel> {
+    if (options.type === 'file') {
+      options.ext = options.ext || '.txt';
     }
-    return this._contentsManager.newUntitled(this._model.path,
-      { type: type, ext: ext }
-    ).then(contents => {
+    options.path = options.path || this._model.path;
+    return this._contentsManager.newUntitled(options).then(contents => {
       this.fileChanged.emit({
         name: 'file',
         oldValue: void 0,
@@ -247,7 +245,7 @@ class FileBrowserModel implements IDisposable {
    *
    * @returns A promise containing the new file contents model.
    */
-  rename(path: string, newPath: string): Promise<IContentsModel> {
+  rename(path: string, newPath: string): Promise<IContents.IModel> {
     // Handle relative paths.
     let normalizePath = Private.normalizePath;
     path = normalizePath(this._model.path, path);
@@ -275,13 +273,13 @@ class FileBrowserModel implements IDisposable {
    * This will fail to upload files that are too big to be sent in one
    * request to the server.
    */
-  upload(file: File, overwrite?: boolean): Promise<IContentsModel> {
+  upload(file: File, overwrite?: boolean): Promise<IContents.IModel> {
     // Skip large files with a warning.
     if (file.size > this._maxUploadSizeMb * 1024 * 1024) {
       let msg = `Cannot upload file (>${this._maxUploadSizeMb} MB) `;
       msg += `"${file.name}"`;
       console.warn(msg);
-      return Promise.reject<IContentsModel>(new Error(msg));
+      return Promise.reject<IContents.IModel>(new Error(msg));
     }
 
     if (overwrite) {
@@ -289,7 +287,7 @@ class FileBrowserModel implements IDisposable {
     }
 
     return this._contentsManager.get(file.name, {}).then(() => {
-      return Private.typedThrow<IContentsModel>(`"${file.name}" already exists`);
+      return Private.typedThrow<IContents.IModel>(`"${file.name}" already exists`);
     }, () => {
       return this._upload(file);
     });
@@ -317,14 +315,14 @@ class FileBrowserModel implements IDisposable {
   /**
    * Perform the actual upload.
    */
-  private _upload(file: File): Promise<IContentsModel> {
+  private _upload(file: File): Promise<IContents.IModel> {
     // Gather the file model parameters.
     let path = this._model.path;
     path = path ? path + '/' + file.name : file.name;
     let name = file.name;
     let isNotebook = file.name.indexOf('.ipynb') !== -1;
-    let type = isNotebook ? 'notebook' : 'file';
-    let format = isNotebook ? 'json' : 'base64';
+    let type: IContents.FileType = isNotebook ? 'notebook' : 'file';
+    let format: IContents.FileFormat = isNotebook ? 'json' : 'base64';
 
     // Get the file content.
     let reader = new FileReader();
@@ -334,12 +332,12 @@ class FileBrowserModel implements IDisposable {
       reader.readAsArrayBuffer(file);
     }
 
-    return new Promise<IContentsModel>((resolve, reject) => {
+    return new Promise<IContents.IModel>((resolve, reject) => {
       reader.onload = (event: Event) => {
-        let model: IContentsOpts = {
+        let model: IContents.IModel = {
           type: type,
-          format: format,
-          name: name,
+          format,
+          name,
           content: Private.getContent(reader)
         };
         this._contentsManager.save(path, model).then(contents => {
@@ -369,7 +367,7 @@ class FileBrowserModel implements IDisposable {
       if (!models.length) {
         return;
       }
-      let paths = this._model.content.map((contents: IContentsModel) => {
+      let paths = this._model.content.map((contents: IContents.IModel) => {
         return contents.path;
       });
       for (let model of models) {
@@ -382,10 +380,10 @@ class FileBrowserModel implements IDisposable {
   }
 
   private _maxUploadSizeMb = 15;
-  private _contentsManager: IContentsManager = null;
+  private _contentsManager: IContents.IManager = null;
   private _sessions: ISession.IModel[] = [];
   private _sessionManager: ISession.IManager = null;
-  private _model: IContentsModel;
+  private _model: IContents.IModel;
   private _specs: IKernel.ISpecModels = null;
 }
 
@@ -403,7 +401,7 @@ namespace FileBrowserModel {
     /**
      * A contents manager instance.
      */
-    contentsManager: IContentsManager;
+    contentsManager: IContents.IManager;
 
     /**
      * A session manager instance.

+ 5 - 1
src/filebrowser/plugin.ts

@@ -124,10 +124,14 @@ function activateFileBrowser(app: Application, provider: JupyterServices, regist
   app.commands.add([
     {
       id: newTextFileId,
+<<<<<<< HEAD
       handler: () => {
         let icon = `${PORTRAIT_ICON_CLASS} ${TEXTEDITOR_ICON_CLASS}`;
         fbWidget.createNew('file').then(widget => widget.title.icon = icon);
       }
+=======
+      handler: () => fbWidget.createNew({ type: 'file' })
+>>>>>>> e8dce4a... Update jupyter-js-services and clean up interfaces
     }
   ]);
 
@@ -138,7 +142,7 @@ function activateFileBrowser(app: Application, provider: JupyterServices, regist
     id: newNotebookId,
     handler: () => {
       let icon = `${PORTRAIT_ICON_CLASS} ${NOTEBOOK_ICON_CLASS}`;
-      fbWidget.createNew('notebook').then(widget => widget.title.icon = icon);
+      fbWidget.createNew({ type: 'notebook' }).then(widget => widget.title.icon = icon);
     }
   }]);
 

+ 13 - 4
src/notebook/notebook/modelfactory.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsOpts
+  IContents
 } from 'jupyter-js-services';
 
 import {
@@ -30,13 +30,22 @@ class NotebookModelFactory implements IModelFactory {
   }
 
   /**
-   * The contents options used to fetch/save files.
+   * The type of the file.
    *
    * #### Notes
    * This is a read-only property.
    */
-  get contentsOptions(): IContentsOpts {
-    return { type: 'notebook' };
+  get fileType(): IContents.FileType {
+    return 'notebook';
+  }
+
+  /**
+   * The format of the file.
+   *
+   * This is a read-only property.
+   */
+  get fileFormat(): IContents.FileFormat {
+    return 'json';
   }
 
   /**

+ 9 - 4
src/notebook/plugin.ts

@@ -14,8 +14,7 @@ import {
 } from 'phosphor-widget';
 
 import {
-  DocumentRegistry, restartKernel, selectKernelForContext,
-  IWidgetExtension
+  DocumentRegistry, restartKernel, selectKernelForContext
 } from '../docregistry';
 
 import {
@@ -134,11 +133,17 @@ function activateNotebookHandler(app: Application, registry: DocumentRegistry, s
   let displayNames = Object.keys(displayNameMap).sort((a, b) => {
     return a.localeCompare(b);
   });
+  registry.addFileType({
+    name: 'Notebook',
+    extension: '.ipynb',
+    fileType: 'notebook',
+    fileFormat: 'json'
+  });
   for (let displayName of displayNames) {
     registry.addCreator({
       name: `${displayName} Notebook`,
-      extension: '.ipynb',
-      type: 'notebook',
+      fileType: 'Notebook',
+      widgetName: 'Notebook',
       kernelName: displayNameMap[displayName]
     });
   }

+ 44 - 0
src/running/index.ts

@@ -0,0 +1,44 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  Widget
+} from 'phosphor-widget';
+
+
+/**
+ * The class name added to a running widget.
+ */
+const RUNNING_CLASS = 'jp-Running';
+
+/**
+ * The class name added to the running terminals list.
+ */
+const TERMINALS_CLASS = 'jp-Running-terminals';
+
+/**
+ * The class name added to the running sessions list.
+ */
+const SESSIONS_CLASS = 'jp-Running-sessions';
+
+
+/**
+ * A class that exposes the running terminals and sessions.
+ */
+export
+class Running extends Widget {
+  /**
+   * Create the node for the running widget.
+   */
+  static createNode(): HTMLElement {
+    let node = document.createElement('div');
+    let terminals = document.createElement('ul');
+    terminals.className = TERMINALS_CLASS;
+    let sessions = document.createElement('ul');
+    sessions.className = SESSIONS_CLASS;
+    node.appendChild(terminals);
+    node.appendChild(sessions);
+    return node;
+  }
+
+}

+ 4 - 4
src/services/plugin.ts

@@ -6,7 +6,7 @@ import {
 } from 'jupyter-js-utils';
 
 import {
-  IKernel, ISession, IContentsManager,
+  IKernel, ISession, IContents,
   ContentsManager, KernelManager, SessionManager,
   getKernelSpecs, IAjaxSettings
 } from 'jupyter-js-services';
@@ -30,7 +30,7 @@ class JupyterServices {
     this._kernelspecs = specs;
     this._kernelManager = new KernelManager(options);
     this._sessionManager = new SessionManager(options);
-    this._contentsManager = new ContentsManager(baseUrl, ajaxSettings);
+    this._contentsManager = new ContentsManager(options);
     this._terminalManager = new TerminalManager(options);
   }
 
@@ -67,7 +67,7 @@ class JupyterServices {
    * #### Notes
    * This is a read-only property.
    */
-  get contentsManager(): IContentsManager {
+  get contentsManager(): IContents.IManager {
     return this._contentsManager;
   }
 
@@ -83,7 +83,7 @@ class JupyterServices {
 
   private _kernelManager: IKernel.IManager = null;
   private _sessionManager: ISession.IManager = null;
-  private _contentsManager: IContentsManager = null;
+  private _contentsManager: IContents.IManager = null;
   private _terminalManager: TerminalManager = null;
   private _kernelspecs: IKernel.ISpecModels = null;
 }

+ 4 - 4
test/src/docmanager/mockcontext.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  IContentsModel, IKernel, ISession
+  IContents, IKernel, ISession
 } from 'jupyter-js-services';
 
 import {
@@ -43,7 +43,7 @@ class MockContext<T extends IDocumentModel> implements IDocumentContext<T> {
     return Private.pathChangedSignal.bind(this);
   }
 
-  get contentsModelChanged(): ISignal<IDocumentContext<T>, IContentsModel> {
+  get contentsModelChanged(): ISignal<IDocumentContext<T>, IContents.IModel> {
     return Private.contentsModelChanged.bind(this);
   }
 
@@ -67,7 +67,7 @@ class MockContext<T extends IDocumentModel> implements IDocumentContext<T> {
     return this._path;
   }
 
-  get contentsModel(): IContentsModel {
+  get contentsModel(): IContents.IModel {
     return void 0;
   }
 
@@ -155,5 +155,5 @@ namespace Private {
    * A signal emitted when the contentsModel changes.
    */
   export
-  const contentsModelChanged = new Signal<IDocumentContext<IDocumentModel>, IContentsModel>();
+  const contentsModelChanged = new Signal<IDocumentContext<IDocumentModel>, IContents.IModel>();
 }

+ 36 - 10
test/src/docregistry/default.spec.ts

@@ -96,17 +96,30 @@ describe('docmanager/default', () => {
 
     });
 
-    describe('#contentsOptions', () => {
+    describe('#type', () => {
 
-      it('should get the contents options used to fetch/save files', () => {
+      it('should get the file type', () => {
         let factory = new Base64ModelFactory();
-        let expected = { type: 'file', format: 'base64' };
-        expect(factory.contentsOptions).to.eql(expected);
+        expect(factory.fileType).to.be('file');
       });
 
       it('should be read-only', () => {
         let factory = new Base64ModelFactory();
-        expect(() => { factory.contentsOptions = null; }).to.throwError();
+        expect(() => { factory.fileType = 'file'; }).to.throwError();
+      });
+
+    });
+
+    describe('#format', () => {
+
+      it('should get the file format', () => {
+        let factory = new Base64ModelFactory();
+        expect(factory.fileFormat).to.be('base64');
+      });
+
+      it('should be read-only', () => {
+        let factory = new Base64ModelFactory();
+        expect(() => { factory.fileFormat = 'base64'; }).to.throwError();
       });
 
     });
@@ -363,17 +376,30 @@ describe('docmanager/default', () => {
 
     });
 
-    describe('#contentsOptions', () => {
+    describe('#type', () => {
+
+      it('should get the file type', () => {
+        let factory = new TextModelFactory();
+        expect(factory.fileType).to.be('file');
+      });
+
+      it('should be read-only', () => {
+        let factory = new TextModelFactory();
+        expect(() => { factory.fileType = 'file'; }).to.throwError();
+      });
+
+    });
+
+    describe('#format', () => {
 
-      it('should get the contents options used to fetch/save files', () => {
+      it('should get the file format', () => {
         let factory = new TextModelFactory();
-        let options = { type: 'file', format: 'text' };
-        expect(factory.contentsOptions).to.eql(options);
+        expect(factory.fileFormat).to.be('text');
       });
 
       it('should be read-only', () => {
         let factory = new TextModelFactory();
-        expect(() => { factory.contentsOptions = null; }).to.throwError();
+        expect(() => { factory.fileFormat = 'text'; }).to.throwError();
       });
 
     });

+ 1 - 453
test/src/notebook/notebook/actions.spec.ts

@@ -16,7 +16,7 @@ import {
 } from 'phosphor-dragdrop';
 
 import {
-  CodeCellWidget, MarkdownCellWidget, RawCellWidget
+  CodeCellWidget, MarkdownCellWidget
 } from '../../../../lib/notebook/cells/widget';
 
 import {
@@ -66,458 +66,6 @@ describe('notebook/notebook/actions', () => {
       clipboard.clear();
     });
 
-    describe('#splitCell()', () => {
-
-      it('should split the active cell into two cells', () => {
-        let cell = widget.activeCell;
-        let source = 'thisisasamplestringwithnospaces';
-        cell.model.source = source;
-        let index = widget.activeCellIndex;
-        cell.editor.setCursorPosition(10);
-        NotebookActions.splitCell(widget);
-        let cells = widget.model.cells;
-        let newSource = cells.get(index).source + cells.get(index + 1).source;
-        expect(newSource).to.be(source);
-      });
-
-      it('should remove leading white space in the second cell', () => {
-        let cell = widget.activeCell;
-        let source = 'this\n\n   is a test';
-        cell.model.source = source;
-        cell.editor.setCursorPosition(4);
-        NotebookActions.splitCell(widget);
-        expect(widget.activeCell.model.source).to.be('is a test');
-      });
-
-      it('should clear the existing selection', () => {
-        for (let i = 0; i < widget.childCount(); i++) {
-          widget.select(widget.childAt(i));
-        }
-        NotebookActions.splitCell(widget);
-        for (let i = 0; i < widget.childCount(); i++) {
-          if (i === widget.activeCellIndex) {
-            continue;
-          }
-          expect(widget.isSelected(widget.childAt(i))).to.be(false);
-        }
-      });
-
-      it('should activate the second cell', () => {
-        NotebookActions.splitCell(widget);
-        expect(widget.activeCellIndex).to.be(1);
-      });
-
-      it('should preserve the types of each cell', () => {
-        NotebookActions.changeCellType(widget, 'markdown');
-        NotebookActions.splitCell(widget);
-        expect(widget.activeCell).to.be.a(MarkdownCellWidget);
-        let prev = widget.childAt(0);
-        expect(prev).to.be.a(MarkdownCellWidget);
-      });
-
-      it('should create two empty cells if there is no content', () => {
-        widget.activeCell.model.source = '';
-        NotebookActions.splitCell(widget);
-        expect(widget.activeCell.model.source).to.be('');
-        let prev = widget.childAt(0);
-        expect(prev.model.source).to.be('');
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.splitCell(widget);
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should preserve the widget mode', () => {
-        NotebookActions.splitCell(widget);
-        expect(widget.mode).to.be('command');
-        widget.mode = 'edit';
-        NotebookActions.splitCell(widget);
-        expect(widget.mode).to.be('edit');
-      });
-
-      it('should be undo-able', () => {
-        let source = widget.activeCell.model.source;
-        let count = widget.childCount();
-        NotebookActions.splitCell(widget);
-        NotebookActions.undo(widget);
-        expect(widget.childCount()).to.be(count);
-        let cell = widget.childAt(0);
-        expect(cell.model.source).to.be(source);
-      });
-
-    });
-
-    describe('#mergeCells', () => {
-
-      it('should merge the selected cells', () => {
-        let source = widget.activeCell.model.source + '\n\n';
-        let next = widget.childAt(1);
-        source += next.model.source;
-        widget.select(next);
-        let count = widget.childCount();
-        NotebookActions.mergeCells(widget);
-        expect(widget.childCount()).to.be(count - 1);
-        expect(widget.activeCell.model.source).to.be(source);
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.mergeCells(widget);
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should select the next cell if there is only one cell selected', () => {
-        let source = widget.activeCell.model.source + '\n\n';
-        let next = widget.childAt(1);
-        source += next.model.source;
-        NotebookActions.mergeCells(widget);
-        expect(widget.activeCell.model.source).to.be(source);
-      });
-
-      it('should clear the outputs of a code cell', () => {
-        NotebookActions.mergeCells(widget);
-        let cell = widget.activeCell as CodeCellWidget;
-        expect(cell.model.outputs.length).to.be(0);
-      });
-
-      it('should preserve the widget mode', () => {
-        widget.mode = 'edit';
-        NotebookActions.mergeCells(widget);
-        expect(widget.mode).to.be('edit');
-        widget.mode = 'command';
-        NotebookActions.mergeCells(widget);
-        expect(widget.mode).to.be('command');
-      });
-
-      it('should be undo-able', () => {
-        let source = widget.activeCell.model.source;
-        let count = widget.childCount();
-        NotebookActions.mergeCells(widget);
-        NotebookActions.undo(widget);
-        expect(widget.childCount()).to.be(count);
-        let cell = widget.childAt(0);
-        expect(cell.model.source).to.be(source);
-      });
-
-      it('should unrender a markdown cell', () => {
-        NotebookActions.changeCellType(widget, 'markdown');
-        let cell = widget.activeCell as MarkdownCellWidget;
-        cell.rendered = true;
-        NotebookActions.mergeCells(widget);
-        cell = widget.activeCell as MarkdownCellWidget;
-        expect(cell.rendered).to.be(false);
-      });
-
-      it('should preserve the cell type of the active cell', () => {
-        NotebookActions.changeCellType(widget, 'raw');
-        NotebookActions.mergeCells(widget);
-        expect(widget.activeCell).to.be.a(RawCellWidget);
-      });
-
-    });
-
-    describe('#deleteCells()', () => {
-
-      it('should delete the selected cells', () => {
-        let next = widget.childAt(1);
-        widget.select(next);
-        let count = widget.childCount();
-        NotebookActions.deleteCells(widget);
-        expect(widget.childCount()).to.be(count - 2);
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.deleteCells(widget);
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should switch to command mode', () => {
-        widget.mode = 'edit';
-        NotebookActions.deleteCells(widget);
-        expect(widget.mode).to.be('command');
-      });
-
-      it('should activate the cell before the first selected cell', () => {
-        widget.activeCellIndex = 4;
-        let prev = widget.childAt(2);
-        widget.select(prev);
-        NotebookActions.deleteCells(widget);
-        expect(widget.activeCellIndex).to.be(1);
-      });
-
-      it('should add a code cell if all cells are deleted', () => {
-        for (let i = 0; i < widget.childCount(); i++) {
-          widget.select(widget.childAt(i));
-        }
-        NotebookActions.deleteCells(widget);
-        expect(widget.childCount()).to.be(1);
-        expect(widget.activeCell).to.be.a(CodeCellWidget);
-      });
-
-      it('should be undo-able', () => {
-        let next = widget.childAt(1);
-        widget.select(next);
-        let source = widget.activeCell.model.source;
-        let count = widget.childCount();
-        NotebookActions.deleteCells(widget);
-        NotebookActions.undo(widget);
-        expect(widget.childCount()).to.be(count);
-        let cell = widget.childAt(0);
-        expect(cell.model.source).to.be(source);
-      });
-
-    });
-
-    describe('#insertAbove()', () => {
-
-      it('should insert a code cell above the active cell', () => {
-        let count = widget.childCount();
-        NotebookActions.insertAbove(widget);
-        expect(widget.activeCellIndex).to.be(0);
-        expect(widget.childCount()).to.be(count + 1);
-        expect(widget.activeCell).to.be.a(CodeCellWidget);
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.insertAbove(widget);
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should widget mode should be preserved', () => {
-        NotebookActions.insertAbove(widget);
-        expect(widget.mode).to.be('command');
-        widget.mode = 'edit';
-        NotebookActions.insertAbove(widget);
-        expect(widget.mode).to.be('edit');
-      });
-
-      it('should be undo-able', () => {
-        let count = widget.childCount();
-        NotebookActions.insertAbove(widget);
-        NotebookActions.undo(widget);
-        expect(widget.childCount()).to.be(count);
-      });
-
-      it('should clear the existing selection', () => {
-        for (let i = 0; i < widget.childCount(); i++) {
-          widget.select(widget.childAt(i));
-        }
-        NotebookActions.insertAbove(widget);
-        for (let i = 0; i < widget.childCount(); i++) {
-          if (i === widget.activeCellIndex) {
-            continue;
-          }
-          expect(widget.isSelected(widget.childAt(i))).to.be(false);
-        }
-      });
-
-      it('should be the new active cell', () => {
-        NotebookActions.insertAbove(widget);
-        expect(widget.activeCell.model.source).to.be('');
-      });
-
-    });
-
-    describe('#insertBelow()', () => {
-
-      it('should insert a code cell below the active cell', () => {
-        let count = widget.childCount();
-        NotebookActions.insertBelow(widget);
-        expect(widget.activeCellIndex).to.be(1);
-        expect(widget.childCount()).to.be(count + 1);
-        expect(widget.activeCell).to.be.a(CodeCellWidget);
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.insertBelow(widget);
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should widget mode should be preserved', () => {
-        NotebookActions.insertBelow(widget);
-        expect(widget.mode).to.be('command');
-        widget.mode = 'edit';
-        NotebookActions.insertBelow(widget);
-        expect(widget.mode).to.be('edit');
-      });
-
-      it('should be undo-able', () => {
-        let count = widget.childCount();
-        NotebookActions.insertBelow(widget);
-        NotebookActions.undo(widget);
-        expect(widget.childCount()).to.be(count);
-      });
-
-      it('should clear the existing selection', () => {
-        for (let i = 0; i < widget.childCount(); i++) {
-          widget.select(widget.childAt(i));
-        }
-        NotebookActions.insertBelow(widget);
-        for (let i = 0; i < widget.childCount(); i++) {
-          if (i === widget.activeCellIndex) {
-            continue;
-          }
-          expect(widget.isSelected(widget.childAt(i))).to.be(false);
-        }
-      });
-
-      it('should be the new active cell', () => {
-        NotebookActions.insertBelow(widget);
-        expect(widget.activeCell.model.source).to.be('');
-      });
-
-    });
-
-    describe('#changeCellType()', () => {
-
-      it('should change the selected cell type(s)', () => {
-        let next = widget.childAt(1);
-        widget.select(next);
-        NotebookActions.changeCellType(widget, 'raw');
-        expect(widget.activeCell).to.be.a(RawCellWidget);
-        next = widget.childAt(widget.activeCellIndex + 1);
-        expect(next).to.be.a(RawCellWidget);
-      });
-
-      it('should be a no-op if there is no model', () => {
-        widget.model = null;
-        NotebookActions.changeCellType(widget, 'code');
-        expect(widget.activeCell).to.be(void 0);
-      });
-
-      it('should preserve the widget mode', () => {
-        NotebookActions.changeCellType(widget, 'code');
-        expect(widget.mode).to.be('command');
-        widget.mode = 'edit';
-        NotebookActions.changeCellType(widget, 'raw');
-        expect(widget.mode).to.be('edit');
-      });
-
-      it('should be undo-able', () => {
-        NotebookActions.changeCellType(widget, 'raw');
-        NotebookActions.undo(widget);
-        let cell = widget.childAt(0);
-        expect(cell).to.be.a(CodeCellWidget);
-      });
-
-      it('should clear the existing selection', () => {
-        for (let i = 0; i < widget.childCount(); i++) {
-          widget.select(widget.childAt(i));
-        }
-        NotebookActions.changeCellType(widget, 'raw');
-        for (let i = 0; i < widget.childCount(); i++) {
-          if (i === widget.activeCellIndex) {
-            continue;
-          }
-          expect(widget.isSelected(widget.childAt(i))).to.be(false);
-        }
-      });
-
-      it('should unrender markdown cells', () => {
-        NotebookActions.changeCellType(widget, 'markdown');
-        let cell = widget.activeCell as MarkdownCellWidget;
-        expect(cell.rendered).to.be(false);
-      });
-
-    });
-
-    describe('#run()', () => {
-
-      it('should run the selected cells', (done) => {
-        let next = widget.childAt(1) as MarkdownCellWidget;
-        widget.select(next);
-        let cell = widget.activeCell as CodeCellWidget;
-        cell.model.outputs.clear();
-        next.rendered = false;
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(true);
-          expect(cell.model.outputs.length).to.be.above(0);
-          expect(next.rendered).to.be(true);
-          done();
-        });
-      });
-
-      it('should be a no-op if there is no model', (done) => {
-        widget.model = null;
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(false);
-          done();
-        });
-      });
-
-      it('should activate the last selected cell', (done) => {
-        let other = widget.childAt(2);
-        widget.select(other);
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(true);
-          expect(widget.activeCell).to.be(other);
-          done();
-        });
-      });
-
-      it('should clear the selection', (done) => {
-        let next = widget.childAt(1);
-        widget.select(next);
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(true);
-          expect(widget.isSelected(widget.childAt(0))).to.be(false);
-          done();
-        });
-      });
-
-      it('should change to command mode', (done) => {
-        widget.mode = 'edit';
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(true);
-          expect(widget.mode).to.be('command');
-          done();
-        });
-      });
-
-      it('should handle no kernel', (done) => {
-        NotebookActions.run(widget, null).then(result => {
-          expect(result).to.be(true);
-          let cell = widget.activeCell as CodeCellWidget;
-          expect(cell.model.executionCount).to.be(null);
-          done();
-        });
-      });
-
-      it('should stop executing code cells on an error', (done) => {
-        let cell = widget.model.factory.createCodeCell();
-        cell.source = ERROR_INPUT;
-        widget.model.cells.insert(2, cell);
-        widget.select(widget.childAt(2));
-        cell = widget.model.factory.createCodeCell();
-        widget.model.cells.add(cell);
-        widget.select(widget.childAt(widget.childCount() - 1));
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(false);
-          expect(cell.executionCount).to.be(null);
-          done();
-        });
-      });
-
-      it('should render all markdown cells on an error', () => {
-        let cell = widget.model.factory.createMarkdownCell();
-        widget.model.cells.add(cell);
-        let child = widget.childAt(widget.childCount() - 1) as MarkdownCellWidget;
-        child.rendered = false;
-        widget.select(child);
-        widget.activeCell.model.source = ERROR_INPUT;
-        NotebookActions.run(widget, kernel).then(result => {
-          expect(result).to.be(false);
-          expect(child.rendered).to.be(true);
-        });
-      });
-
-    });
-
     describe('#runAndAdvance()', () => {
 
       it('should run the selected cells ', (done) => {

+ 18 - 4
test/src/notebook/notebook/modelfactory.spec.ts

@@ -30,16 +30,30 @@ describe('notebook/notebook/modelfactory', () => {
 
     });
 
-    describe('#contentsOptions', () => {
+    describe('#type', () => {
 
-      it('should get the contents options used to fetch/save files', () => {
+      it('should get the file type', () => {
         let factory = new NotebookModelFactory();
-        expect(factory.contentsOptions).to.eql({ type: 'notebook' });
+        expect(factory.fileType).to.be('notebook');
       });
 
       it('should be read-only', () => {
         let factory = new NotebookModelFactory();
-        expect(() => { factory.contentsOptions = null; }).to.throwError();
+        expect(() => { factory.fileType = 'notebook'; }).to.throwError();
+      });
+
+    });
+
+    describe('#format', () => {
+
+      it('should get the file format', () => {
+        let factory = new NotebookModelFactory();
+        expect(factory.fileFormat).to.be('json');
+      });
+
+      it('should be read-only', () => {
+        let factory = new NotebookModelFactory();
+        expect(() => { factory.fileFormat = 'json'; }).to.throwError();
       });
 
     });