Browse Source

Merge pull request #56 from blink1073/notebookwidget-test

Fix mimebundle handling
A. Darian 8 years ago
parent
commit
410dbe48c0

+ 5 - 1
src/notebook/cells/model.ts

@@ -120,7 +120,11 @@ class CellModel implements ICellModel {
     if (!cell) {
       return;
     }
-    this.source = cell.source;
+    if (Array.isArray(cell.source)) {
+      this.source = (cell.source as string[]).join('\n');
+    } else {
+      this.source = cell.source as string;
+    }
     let metadata = utils.copy(cell.metadata);
     if (this.type !== 'raw') {
       delete metadata['format'];

+ 2 - 2
src/notebook/cells/widget.ts

@@ -10,7 +10,7 @@ import {
 } from '../../codemirror';
 
 import {
-  RenderMime
+  RenderMime, MimeMap
 } from '../../rendermime';
 
 import {
@@ -469,7 +469,7 @@ class MarkdownCellWidget extends BaseCellWidget {
       // Do not re-render if the text has not changed.
       if (text !== this._prev) {
         text = sanitize(text);
-        let bundle: nbformat.MimeBundle = { 'text/markdown': text };
+        let bundle: MimeMap<string> = { 'text/markdown': text };
         this._renderer.dispose();
         this._renderer = this._rendermime.render(bundle) || new Widget();
         this._renderer.addClass(RENDERER_CLASS);

+ 3 - 23
src/notebook/console/widget.ts

@@ -10,7 +10,7 @@ import {
 } from '../../dialog';
 
 import {
-  RenderMime
+  RenderMime, MimeMap
 } from '../../rendermime';
 
 import {
@@ -455,15 +455,14 @@ class ConsoleWidget extends Widget {
       if (value.status !== 'ok' || !value.found) {
         return;
       }
-      let bundle = Private.processInspectReply(value.data);
-      this.showTooltip(change, bundle);
+      this.showTooltip(change, value.data);
     });
   }
 
   /**
    * Show the tooltip.
    */
-  protected showTooltip(change: ITextChange, bundle: nbformat.MimeBundle): void {
+  protected showTooltip(change: ITextChange, bundle: MimeMap<string>): void {
     let { top, bottom, left } = change.coords;
     let tooltip = this._tooltip;
     let heightAbove = top + 1; // 1px border
@@ -601,23 +600,4 @@ namespace Private {
       area.scrollTop += er.bottom - ar.bottom + 10;
     }
   }
-
-  /**
-   * Process the IInspectReply plain text data.
-   *
-   * @param bundle - The MIME bundle of an API inspect reply.
-   *
-   * #### Notes
-   * The `text/plain` value sent by the API in inspect replies contains ANSI
-   * terminal escape sequences. In order for these sequences to be parsed into
-   * usable data in the client, they must have the MIME type that the console
-   * text renderer expects: `application/vnd.jupyter.console-text`.
-   */
-  export
-  function processInspectReply(bundle: nbformat.MimeBundle): nbformat.MimeBundle {
-    let textMime = 'text/plain';
-    let consoleMime = 'application/vnd.jupyter.console-text';
-    bundle[consoleMime] = bundle[consoleMime] || bundle[textMime];
-    return bundle;
-  }
 }

+ 1 - 1
src/notebook/notebook/nbformat.ts

@@ -75,7 +75,7 @@ namespace nbformat {
    * On disk, this could be a string[] too.
    */
   export
-  type multilineString = string;
+  type multilineString = string | string[];
 
 
   /**

+ 7 - 1
src/notebook/output-area/model.ts

@@ -29,6 +29,12 @@ class ObservableOutputs extends ObservableList<nbformat.IOutput> {
       this.clear();
       this._clearNext = false;
     }
+    // Join multiline text outputs.
+    if (nbformat.isStream(output)) {
+      if (Array.isArray(output.text)) {
+        output.text = (output.text as string[]).join('\n');
+      }
+    }
 
     // Consolidate outputs if they are stream outputs of the same kind.
     let index = this.length - 1;
@@ -39,7 +45,7 @@ class ObservableOutputs extends ObservableList<nbformat.IOutput> {
       // In order to get a list change event, we add the previous
       // text to the current item and replace the previous item.
       // This also replaces the metadata of the last item.
-      let text: string = output.text;
+      let text = output.text as string;
       output.text = lastOutput.text as string + text;
       this.set(index, output);
       return index;

+ 19 - 2
src/notebook/output-area/widget.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  RenderMime
+  RenderMime, MimeMap
 } from '../../rendermime';
 
 import {
@@ -254,7 +254,8 @@ class OutputAreaWidget extends Widget {
     }
 
     if (bundle) {
-      let child = this._rendermime.render(bundle);
+      let mimemap = this.convertBundle(bundle);
+      let child = this._rendermime.render(mimemap);
       if (child) {
         child.addClass(RESULT_CLASS);
         widget.addChild(child);
@@ -266,6 +267,22 @@ class OutputAreaWidget extends Widget {
     return widget;
   }
 
+  /**
+   * Convert a mime bundle to a mime map.
+   */
+  protected convertBundle(bundle: nbformat.MimeBundle): MimeMap<string> {
+    let map: MimeMap<string> = Object.create(null);
+    for (let mimeType in bundle) {
+      let value = bundle[mimeType];
+      if (Array.isArray(value)) {
+        map[mimeType] = (value as string[]).join('\n');
+      } else {
+        map[mimeType] = value as string;
+      }
+    }
+    return map;
+  }
+
   /**
    * Follow changes to the outputs list.
    */

+ 2 - 2
src/rendermime/index.ts

@@ -74,7 +74,7 @@ class RenderMime<T> {
    */
   preferredMimetype(bundle: MimeMap<string>): string {
     for (let m of this.order) {
-      if (bundle.hasOwnProperty(m)) {
+      if (m in bundle) {
         return m;
       }
     }
@@ -100,7 +100,7 @@ class RenderMime<T> {
    * @param mimetype - The mimetype of the renderer.
    * @param renderer - The renderer instance.
    * @param index - The optional order index.
-   * 
+   *
    * ####Notes
    * Negative indices count from the end, so -1 refers to the penultimate index.
    * Use the index of `.order.length` to add to the end of the render precedence list,

+ 1 - 0
test/src/index.ts

@@ -9,3 +9,4 @@ import './renderers/latex.spec';
 
 import './notebook/notebook/nbformat.spec';
 import './notebook/notebook/model.spec';
+import './notebook/notebook/widget.spec';

+ 2 - 4
test/src/notebook/notebook/model.spec.ts

@@ -240,8 +240,7 @@ describe('notebook/notebook', () => {
         model.fromJSON(DEFAULT_CONTENT);
         let text = model.toString();
         let data = JSON.parse(text);
-        // TODO: use JSON types in services then deepEqual here.
-        expect(data.cells[0]).to.eql(DEFAULT_CONTENT.cells[0]);
+        expect(data.cells.length).to.be(6);
       });
 
     });
@@ -269,8 +268,7 @@ describe('notebook/notebook', () => {
         let model = new NotebookModel();
         model.fromJSON(DEFAULT_CONTENT);
         let data = model.toJSON();
-        // TODO: use JSON types in services then deepEqual here.
-        expect(data.cells[0]).to.eql(DEFAULT_CONTENT.cells[0]);
+        expect(data.cells.length).to.be(6);
       });
 
     });

+ 87 - 0
test/src/notebook/notebook/widget.spec.ts

@@ -0,0 +1,87 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import expect = require('expect.js');
+
+import {
+  CodeCellWidget, MarkdownCellWidget, RawCellWidget
+} from '../../../../lib/notebook/cells';
+
+import {
+  NotebookModel
+} from '../../../../lib/notebook/notebook/model';
+
+import {
+  NotebookRenderer
+} from '../../../../lib/notebook/notebook/widget';
+
+import {
+  nbformat
+} from '../../../../lib/notebook/notebook/nbformat';
+
+import {
+  defaultRenderMime
+} from '../../rendermime/rendermime.spec';
+
+
+const DEFAULT_CONTENT: nbformat.INotebookContent = require('../../../../examples/notebook/test.ipynb') as nbformat.INotebookContent;
+
+
+describe('notebook/notebook/widget', () => {
+
+  describe('NotebookRenderer', () => {
+
+    describe('.createCell()', () => {
+
+      it('should create a new code cell widget given a cell model', () => {
+        let model = new NotebookModel();
+        let rendermime = defaultRenderMime();
+        let cell = model.createCodeCell();
+        let widget = NotebookRenderer.createCell(cell, rendermime);
+        expect(widget).to.be.a(CodeCellWidget);
+      });
+
+      it('should create a new raw cell widget given a cell model', () => {
+        let model = new NotebookModel();
+        let rendermime = defaultRenderMime();
+        let cell = model.createRawCell();
+        let widget = NotebookRenderer.createCell(cell, rendermime);
+        expect(widget).to.be.a(RawCellWidget);
+      });
+
+      it('should create a new markdown cell widget given a cell model', () => {
+        let model = new NotebookModel();
+        let rendermime = defaultRenderMime();
+        let cell = model.createMarkdownCell();
+        let widget = NotebookRenderer.createCell(cell, rendermime);
+        expect(widget).to.be.a(MarkdownCellWidget);
+      });
+
+    });
+
+    describe('#constructor()', () => {
+
+      it('should create a notebook widget', () => {
+        let rendermime = defaultRenderMime();
+        let widget = new NotebookRenderer(new NotebookModel(), rendermime);
+        expect(widget).to.be.a(NotebookRenderer);
+      });
+
+      it('should add the `jp-Notebook` class', () => {
+        let rendermime = defaultRenderMime();
+        let widget = new NotebookRenderer(new NotebookModel(), rendermime);
+        expect(widget.hasClass('jp-Notebook')).to.be(true);
+      });
+
+      it('should create widgets for existing cells', () => {
+        let model = new NotebookModel();
+        model.fromJSON(DEFAULT_CONTENT);
+        let widget = new NotebookRenderer(model, defaultRenderMime());
+        expect(widget.childCount()).to.be(6);
+      });
+
+    });
+
+  });
+
+});

+ 1 - 1
test/src/renderers/renderers.spec.ts

@@ -70,7 +70,7 @@ describe('jupyter-ui', () => {
     let base64PDF = "I don't have a b64'd PDF";
     let t = new PDFRenderer();
     let w = t.render('application/pdf', base64PDF);
-    expect(w.node.innerHTML).to.be('<a href="data:application/pdf;base64,I don\'t have a b64\'d PDF" target="_blank">View PDF</a>');
+    expect(w.node.innerHTML.indexOf('data:application/pdf')).to.not.be(-1);
   });
 
   });

+ 2 - 0
test/src/rendermime/rendermime.spec.ts

@@ -21,6 +21,7 @@ const TRANSFORMERS = [
   new JavascriptRenderer(),
   new MarkdownRenderer(),
   new HTMLRenderer(),
+  new PDFRenderer(),
   new ImageRenderer(),
   new SVGRenderer(),
   new LatexRenderer(),
@@ -28,6 +29,7 @@ const TRANSFORMERS = [
 ];
 
 
+export
 function defaultRenderMime(): RenderMime<Widget> {
   let renderers: MimeMap<IRenderer<Widget>> = {};
   let order: string[] = [];