Steven Silvester il y a 9 ans
Parent
commit
51ffb1d868
2 fichiers modifiés avec 121 ajouts et 139 suppressions
  1. 107 123
      src/notebook/output-area/widget.ts
  2. 14 16
      test/src/notebook/output-area/widget.spec.ts

+ 107 - 123
src/notebook/output-area/widget.ts

@@ -141,6 +141,10 @@ class OutputAreaWidget extends Widget {
     }
     let oldValue = this._model;
     this._model = newValue;
+    if (oldValue) {
+      oldValue.changed.disconnect(this._onModelChange, this);
+    }
+    newValue.changed.connect(this._onModelChange, this);
     this.onModelChanged(oldValue, newValue);
     this.modelChanged.emit(void 0);
   }
@@ -176,7 +180,7 @@ class OutputAreaWidget extends Widget {
       return;
     }
     this._trusted = value;
-    this.onTrustedChanged(value);
+    this.onTrustChanged(value);
   }
 
   /**
@@ -269,6 +273,9 @@ class OutputAreaWidget extends Widget {
 
   /**
    * Handle a change to the model.
+   *
+   * The default implementation is to remove all of the old widgets
+   * and add new widgets for the new outputs.
    */
   protected onModelChanged(oldValue: OutputAreaModel, newValue: OutputAreaModel): void {
     let layout = this.layout as PanelLayout;
@@ -279,54 +286,40 @@ class OutputAreaWidget extends Widget {
     if (!newValue) {
       return;
     }
-    newValue.changed.connect(this.onModelChange, this);
+    let renderer = this.renderer;
+    let rendermime = this.rendermime;
+    let trusted = this.trusted;
     for (let i = 0; i < newValue.length; i++) {
-      let widget = this.createOutput(newValue.get(i));
+      let output = newValue.get(i);
+      let widget = renderer.createOutput(output, rendermime, trusted);
       layout.addChild(widget);
     }
   }
 
   /**
-   * Handle a change to the trusted state.
-   */
-  protected onTrustedChanged(value: boolean): void {
-    // Re-render only if necessary.
-    let model = this.model;
-    if (!model) {
-      return;
-    }
-    let layout = this.layout as PanelLayout;
-    for (let i = 0; i < layout.childCount(); i++) {
-      layout.childAt(0).dispose();
-    }
-    for (let i = 0; i < model.length; i++) {
-      layout.addChild(this.createOutput(model.get(i)));
-    }
-  }
-
-  /**
-   * Create an output widget for an output model.
+   * Handle a change in trust.
+   *
+   * The default implementation is to call `onModelChanged`.
    */
-  protected createOutput(output: nbformat.IOutput): Widget {
-    let renderer = this.renderer;
-    let bundle = renderer.getBundle(output);
-    let map = OutputAreaWidget.convertBundle(bundle);
-    if (!this.trusted) {
-      renderer.sanitize(map);
-    }
-    return renderer.createOutput(output, map, this.rendermime);
+  protected onTrustChanged(value: boolean): void {
+    this.onModelChanged(this.model, this.model);
   }
 
   /**
    * Follow changes to the model.
    */
-  protected onModelChange(sender: OutputAreaModel, args: IListChangedArgs<nbformat.IOutput>) {
+  private _onModelChange(sender: OutputAreaModel, args: IListChangedArgs<nbformat.IOutput>) {
     let layout = this.layout as PanelLayout;
+    let value: nbformat.IOutput;
+    let renderer = this.renderer;
+    let rendermime = this.rendermime;
+    let trusted = this.trusted;
     let widget: Widget;
     switch (args.type) {
     case ListChangeType.Add:
-      let value = args.newValue as nbformat.IOutput;
-      layout.insertChild(args.newIndex, this.createOutput(value));
+      value = args.newValue as nbformat.IOutput;
+      widget = renderer.createOutput(value, rendermime, trusted);
+      layout.addChild(widget);
       break;
     case ListChangeType.Replace:
       // Only "clear" is supported by the model.
@@ -336,9 +329,10 @@ class OutputAreaWidget extends Widget {
       }
       break;
     case ListChangeType.Set:
-      layout.childAt(args.newIndex).parent = null;
-      widget = this.createOutput(args.newValue as nbformat.IOutput);
-      layout.insertChild(args.newIndex, widget);
+      layout.childAt(args.oldIndex).parent = null;
+      value = args.newValue as nbformat.IOutput;
+      widget = renderer.createOutput(value, rendermime, trusted);
+      layout.addChild(widget);
       break;
     default:
       break;
@@ -384,57 +378,82 @@ namespace OutputAreaWidget {
   export
   interface IRenderer {
     /**
-     * Get the mime bundle for an output.
+     * Create an output widget.
      *
-     * @params output - A kernel output message payload.
+     * @param output - The kernel output message payload.
      *
-     * @returns - A mime bundle for the payload.
-     */
-    getBundle(output: nbformat.IOutput): nbformat.MimeBundle;
-
-    /**
-     * Sanitize a mime map.
+     * @param rendermime - The rendermime instance.
      *
-     * @params map - The map to sanitize.
+     * @param trusted - Whether the output is trusted.
+     *
+     * @returns A widget containing the rendered data.
      */
-    sanitize(map: MimeMap<string>): void;
+    createOutput(output: nbformat.IOutput, rendermime: RenderMime<Widget>, trusted?: boolean): Widget;
+  }
 
+  /**
+   * The default implementation of `IRenderer`.
+   */
+  export
+  class Renderer implements IRenderer {
     /**
      * Create an output widget.
      *
-     * @param output - The original kernel output message payload.
-     *
-     * @param data - The processed data from the output.
+     * @param output - The kernel output message payload.
      *
      * @param rendermime - The rendermime instance.
      *
+     * @param trusted - Whether the output is trusted.
+     *
      * @returns A widget containing the rendered data.
      */
-    createOutput(output: nbformat.IOutput, data: MimeMap<string>, rendermime: RenderMime<Widget>): Widget;
-  }
+    createOutput(output: nbformat.IOutput, rendermime: RenderMime<Widget>, trusted = false): Widget {
+      let bundle = this.getBundle(output);
+      let data = this.convertBundle(bundle);
+      if (!trusted) {
+        this.sanitize(data);
+      }
+      let widget = new Panel();
+      switch (output.output_type) {
+      case 'execute_result':
+        widget.addClass(EXECUTE_CLASS);
+        let prompt = new Widget();
+        prompt.addClass(PROMPT_CLASS);
+        let count = (output as nbformat.IExecuteResult).execution_count;
+        prompt.node.textContent = `Out[${count === null ? ' ' : count}]:`;
+        widget.addChild(prompt);
+        break;
+      case 'display_data':
+        widget.addClass(DISPLAY_CLASS);
+        break;
+      case 'stream':
+        if ((output as nbformat.IStream).name === 'stdout') {
+          widget.addClass(STDOUT_CLASS);
+        } else {
+          widget.addClass(STDERR_CLASS);
+        }
+        break;
+      case 'error':
+        widget.addClass(ERROR_CLASS);
+        break;
+      default:
+        console.error(`Unrecognized output type: ${output.output_type}`);
+        data = {};
+      }
 
-  /**
-   * Convert a mime bundle to a mime map.
-   */
-  export
-  function 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;
+      if (data) {
+        let child = rendermime.render(data);
+        if (child) {
+          child.addClass(RESULT_CLASS);
+          widget.addChild(child);
+        } else {
+          console.log('Did not find renderer for output mimebundle.');
+          console.log(data);
+        }
       }
+      return widget;
     }
-    return map;
-  }
 
-  /**
-   * The default implementation of `IRenderer`.
-   */
-  export
-  class Renderer implements IRenderer {
     /**
      * Get the mime bundle for an output.
      *
@@ -466,10 +485,28 @@ namespace OutputAreaWidget {
       return bundle;
     }
 
+    /**
+     * Convert a mime bundle to a mime map.
+     */
+    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;
+    }
+
     /**
      * Sanitize a mime map.
      *
      * @params map - The map to sanitize.
+     *
+     * @returns Whether the
      */
     sanitize(map: MimeMap<string>): void {
       let keys = Object.keys(map);
@@ -491,59 +528,6 @@ namespace OutputAreaWidget {
         }
       }
     }
-
-    /**
-     * Create an output widget.
-     *
-     * @param output - The original kernel output message payload.
-     *
-     * @param data - The processed data from the output.
-     *
-     * @param rendermime - The rendermime instance.
-     *
-     * @returns A widget containing the rendered data.
-     */
-    createOutput(output: nbformat.IOutput, data: MimeMap<string>, rendermime: RenderMime<Widget>): Widget {
-      let widget = new Panel();
-      switch (output.output_type) {
-      case 'execute_result':
-        widget.addClass(EXECUTE_CLASS);
-        let prompt = new Widget();
-        prompt.addClass(PROMPT_CLASS);
-        let count = (output as nbformat.IExecuteResult).execution_count;
-        prompt.node.textContent = `Out[${count === null ? ' ' : count}]:`;
-        widget.addChild(prompt);
-        break;
-      case 'display_data':
-        widget.addClass(DISPLAY_CLASS);
-        break;
-      case 'stream':
-        if ((output as nbformat.IStream).name === 'stdout') {
-          widget.addClass(STDOUT_CLASS);
-        } else {
-          widget.addClass(STDERR_CLASS);
-        }
-        break;
-      case 'error':
-        widget.addClass(ERROR_CLASS);
-        break;
-      default:
-        console.error(`Unrecognized output type: ${output.output_type}`);
-        data = {};
-      }
-
-      if (data) {
-        let child = rendermime.render(data);
-        if (child) {
-          child.addClass(RESULT_CLASS);
-          widget.addChild(child);
-        } else {
-          console.log('Did not find renderer for output mimebundle.');
-          console.log(data);
-        }
-      }
-      return widget;
-    }
   }
 
   /**

+ 14 - 16
test/src/notebook/output-area/widget.spec.ts

@@ -62,20 +62,9 @@ class LogOutputAreaWidget extends OutputAreaWidget {
     this.methods.push('onModelChanged');
   }
 
-  protected onTrustedChanged(value: boolean): void {
-    super.onTrustedChanged(value);
-    this.methods.push('onTrustedChanged');
-  }
-
-  protected createOutput(output: nbformat.IOutput): Widget {
-    let widget = super.createOutput(output);
-    this.methods.push('createOutput');
-    return widget;
-  }
-
-  protected onModelChange(sender: OutputAreaModel, args: IListChangedArgs<nbformat.IOutput>) {
-    super.onModelChange(sender, args);
-    this.methods.push('onModelChange');
+  protected onTrustChanged(value: boolean): void {
+    super.onTrustChanged(value);
+    this.methods.push('onTrustChanged');
   }
 }
 
@@ -411,9 +400,13 @@ describe('notebook/output-area/widget', () => {
 
     });
 
-    describe('.convertBundle()', () => {
+    describe('#onModelChange()', () => {
+
+      it('should be called when trust changes', () => {
+        let widget = new LogOutputAreaWidget({ rendermime });
+      });
 
-      it('should convert a mime bundle to a mime map', () => {
+      it('should should call `onModelChanged`', () => {
 
       });
 
@@ -423,6 +416,11 @@ describe('notebook/output-area/widget', () => {
 
       describe('#getBundle()', () => {
 
+      });
+
+      describe('#convertBundle()', () => {
+
+
       });
 
       describe('#sanitize()', () => {