瀏覽代碼

Update the rendermime objects

Steven Silvester 7 年之前
父節點
當前提交
76198e36fd

+ 38 - 82
packages/rendermime/src/mimemodel.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  JSONObject, JSONValue
+  ReadonlyJSONObject
 } from '@phosphor/coreutils';
 
 import {
@@ -19,19 +19,46 @@ class MimeModel implements IRenderMime.IMimeModel {
    * Construct a new mime model.
    */
   constructor(options: MimeModel.IOptions = {}) {
-    this.data = new MimeModel.Bundle(options.data || {});
-    this.metadata = new MimeModel.Bundle(options.metadata || {});
+    this.trusted = !!options.trusted;
+    this._data = options.data || {};
+    this._metadata = options.metadata || {};
   }
 
+  /**
+   * Whether the model is trusted.
+   */
+  readonly trusted: boolean;
+
   /**
    * The data associated with the model.
    */
-  readonly data: IRenderMime.IBundle;
+  get data(): ReadonlyJSONObject {
+    return this._data;
+  }
 
   /**
    * The metadata associated with the model.
    */
-  readonly metadata: IRenderMime.IBundle;
+  get metadata(): ReadonlyJSONObject {
+    return this._metadata;
+  }
+
+  /**
+   * Set the data associated with the model.
+   */
+  setData(data: ReadonlyJSONObject): void {
+    this._data = data;
+  }
+
+  /**
+   * Set the metadata associated with the model.
+   */
+  setMetadata(data: ReadonlyJSONObject): void {
+    this._metadata = data;
+  }
+
+  private _data: ReadonlyJSONObject;
+  private _metadata: ReadonlyJSONObject;
 }
 
 
@@ -46,89 +73,18 @@ namespace MimeModel {
   export
   interface IOptions {
     /**
-     * The initial mime data.
-     */
-    data?: JSONObject;
-
-    /**
-     * The initial metadata.
+     * Whether the model is trusted.  Defaults to `false`.
      */
-    metadata?: JSONObject;
-  }
-
-  /**
-   * The default implementation of an ibundle.
-   */
-  export
-  class Bundle implements IRenderMime.IBundle {
-    /**
-     * Create a new bundle.
-     */
-    constructor(values: JSONObject) {
-      this._values = values;
-    }
-
-    /**
-     * Get a value for a given key.
-     *
-     * @param key - the key.
-     *
-     * @returns the value for that key.
-     */
-    get(key: string): JSONValue {
-      return this._values[key];
-    }
+    trusted?: boolean;
 
     /**
-     * Check whether the bundle has a key.
-     *
-     * @param key - the key to check.
-     *
-     * @returns `true` if the bundle has the key, `false` otherwise.
-     */
-    has(key: string): boolean {
-      return Object.keys(this._values).indexOf(key) !== -1;
-    }
-
-    /**
-     * Set a key-value pair in the bundle.
-     *
-     * @param key - The key to set.
-     *
-     * @param value - The value for the key.
-     *
-     * @returns the old value for the key, or undefined
-     *   if that did not exist.
-     */
-    set(key: string, value: JSONValue): JSONValue {
-      let old = this._values[key];
-      this._values[key] = value;
-      return old;
-    }
-
-    /**
-     * Get a list of the keys in the bundle.
-     *
-     * @returns - a list of keys.
+     * The initial mime data.
      */
-    keys(): string[] {
-      return Object.keys(this._values);
-    }
+    data?: ReadonlyJSONObject;
 
     /**
-     * Remove a key from the bundle.
-     *
-     * @param key - the key to remove.
-     *
-     * @returns the value of the given key,
-     *   or undefined if that does not exist.
+     * The initial mime metadata.
      */
-    delete(key: string): JSONValue {
-      let old = this._values[key];
-      delete this._values[key];
-      return old;
-    }
-
-    private _values: JSONObject;
+    metadata?: ReadonlyJSONObject;
   }
 }

+ 67 - 26
packages/rendermime/src/outputmodel.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  JSONExt, JSONObject, JSONValue
+  JSONExt, JSONObject, JSONValue, ReadonlyJSONObject
 } from '@phosphor/coreutils';
 
 import {
@@ -33,16 +33,6 @@ interface IOutputModel extends IRenderMime.IMimeModel {
    */
   readonly executionCount: nbformat.ExecutionCount;
 
-  /**
-   * The data associated with the model.
-   */
-  readonly data: IObservableJSON;
-
-  /**
-   * The metadata associated with the model.
-   */
-  readonly metadata: IObservableJSON;
-
   /**
    * Whether the output is trusted.
    */
@@ -92,10 +82,12 @@ class OutputModel implements IOutputModel {
    * Construct a new output model.
    */
   constructor(options: IOutputModel.IOptions) {
-    let { data, metadata } = Private.getBundleOptions(options);
-    this.trusted = !!options.trusted;
-    this.data = new ObservableJSON({ values: data });
-    this.metadata = new ObservableJSON({ values: metadata });
+    let { data, metadata, trusted } = Private.getBundleOptions(options);
+    this._data = new ObservableJSON({ values: data as JSONObject });
+    this._rawData = data;
+    this._metadata = new ObservableJSON({ values: metadata as JSONObject });
+    this._rawMetadata = metadata;
+    this.trusted = trusted;
     // Make a copy of the data.
     let value = options.value;
     for (let key in value) {
@@ -126,27 +118,47 @@ class OutputModel implements IOutputModel {
    */
   readonly executionCount: nbformat.ExecutionCount;
 
+  /**
+   * Whether the model is trusted.
+   */
+  readonly trusted: boolean;
+
+  /**
+   * Dispose of the resources used by the output model.
+   */
+  dispose(): void {
+    this._data.dispose();
+    this._metadata.dispose();
+  }
+
   /**
    * The data associated with the model.
    */
-  readonly data: IObservableJSON;
+  get data(): ReadonlyJSONObject {
+    return this._rawData;
+  }
 
   /**
    * The metadata associated with the model.
    */
-  readonly metadata: IObservableJSON;
+  get metadata(): ReadonlyJSONObject {
+    return this._rawMetadata;
+  }
 
   /**
-   * Whether the model is trusted.
+   * Set the data associated with the model.
    */
-  readonly trusted: boolean;
+  setData(data: ReadonlyJSONObject): void {
+    this._updateObservable(this._data, data);
+    this._rawData = data;
+  }
 
   /**
-   * Dispose of the resources used by the output model.
+   * Set the metadata associated with the model.
    */
-  dispose(): void {
-    this.data.dispose();
-    this.metadata.dispose();
+  setMetadata(data: ReadonlyJSONObject): void {
+    this._updateObservable(this._metadata, data);
+    this._rawMetadata = data;
   }
 
   /**
@@ -161,8 +173,8 @@ class OutputModel implements IOutputModel {
     case 'display_data':
     case 'execute_result':
     case 'update_display_data':
-      output['data'] = this.data.toJSON();
-      output['metadata'] = this.metadata.toJSON();
+      output['data'] = this.data as JSONObject;
+      output['metadata'] = this.metadata as JSONObject;
       break;
     default:
       break;
@@ -172,7 +184,35 @@ class OutputModel implements IOutputModel {
     return output as nbformat.IOutput;
   }
 
+  /**
+   * Update an observable JSON object using a readonly JSON object.
+   */
+  private _updateObservable(observable: IObservableJSON, data: ReadonlyJSONObject) {
+    let oldKeys = observable.keys();
+    let newKeys = Object.keys(data);
+
+    // Handle removed keys.
+    for (let key of oldKeys) {
+      if (newKeys.indexOf(key) === -1) {
+        observable.delete(key);
+      }
+    }
+
+    // Handle changed data.
+    for (let key of newKeys) {
+      let oldValue = observable.get(key);
+      let newValue = data[key];
+      if (oldValue !== newValue) {
+        observable.set(key, newValue as JSONValue);
+      }
+    }
+  }
+
   private _raw: JSONObject = {};
+  private _rawMetadata: ReadonlyJSONObject;
+  private _rawData: ReadonlyJSONObject;
+  private _data: IObservableJSON;
+  private _metadata: IObservableJSON;
 }
 
 
@@ -255,7 +295,8 @@ namespace OutputModel {
   function getBundleOptions(options: IOutputModel.IOptions): MimeModel.IOptions {
     let data = getData(options.value);
     let metadata = getMetadata(options.value);
-    return { data, metadata };
+    let trusted = !!options.trusted;
+    return { data, metadata, trusted };
   }
 
   /**

+ 55 - 38
packages/rendermime/src/rendermime.ts

@@ -44,6 +44,24 @@ class RenderMime {
     this.sanitizer = options.sanitizer || defaultSanitizer;
     this._resolver = options.resolver || null;
     this._handler = options.linkHandler || null;
+    if (options.useDefaultFactories === false) {
+      return;
+    }
+    let renderers = [
+      new JavaScriptRendererFactory(),
+      new HTMLRendererFactory(),
+      new MarkdownRendererFactory(),
+      new LatexRendererFactory(),
+      new SVGRendererFactory(),
+      new ImageRendererFactory(),
+      new PDFRendererFactory(),
+      new TextRendererFactory()
+    ];
+    for (let renderer of renderers) {
+      for (let mime of renderer.mimeTypes) {
+        this._addFactory(renderer, mime);
+      }
+    }
   }
 
   /**
@@ -119,7 +137,7 @@ class RenderMime {
   preferredMimeType(model: IRenderMime.IMimeModel, trusted: boolean): string {
     let sanitizer = this.sanitizer;
     return find(this._mimeTypes, mimeType => {
-      if (model.data.has(mimeType)) {
+      if (mimeType in model.data) {
         let options = { mimeType, sanitizer, trusted };
         let renderer = this._factories[mimeType];
         let canRender = false;
@@ -161,16 +179,43 @@ class RenderMime {
    *
    * @param mimeType - The renderer mimeType.
    *
-   * @param rank - The rank of the renderer.  Defaults to 100.
+   * @param rank - The rank of the renderer. Defaults to 100.
    *
    * #### Notes
    * The renderer will replace an existing renderer for the given
    * mimeType.
    */
-  addFactory(factory: IRenderMime.IRendererFactory, mimeType: string, rank = 100): void {
+  addFactory(factory: IRenderMime.IRendererFactory, mimeType: string, rank?: number): void {
+    this._addFactory(factory, mimeType, rank);
+  }
+
+  /**
+   * Remove a renderer factory by mimeType.
+   *
+   * @param mimeType - The mimeType of the factory.
+   */
+  removeFactory(mimeType: string): void {
+    this._removeFactory(mimeType);
+  }
+
+  /**
+   * Get a renderer factory by mimeType.
+   *
+   * @param mimeType - The mimeType of the renderer.
+   *
+   * @returns The renderer for the given mimeType, or undefined if the mimeType is unknown.
+   */
+  getFactory(mimeType: string): IRenderMime.IRendererFactory {
+    return this._factories[mimeType];
+  }
+
+  /**
+   * Add a factory to the rendermime instance.
+   */
+  private _addFactory(factory: IRenderMime.IRendererFactory, mimeType: string, rank = 100): void {
     // Remove any existing factory.
     if (mimeType in this._factories) {
-      this.removeFactory(mimeType);
+      this._removeFactory(mimeType);
     }
 
     // Add the new factory in the correct order.
@@ -188,7 +233,7 @@ class RenderMime {
    *
    * @param mimeType - The mimeType of the factory.
    */
-  removeFactory(mimeType: string): void {
+  private _removeFactory(mimeType: string): void {
     delete this._factories[mimeType];
     let index = ArrayExt.removeFirstOf(this._mimeTypes, mimeType);
     if (index !== -1) {
@@ -196,17 +241,6 @@ class RenderMime {
     }
   }
 
-  /**
-   * Get a renderer factory by mimeType.
-   *
-   * @param mimeType - The mimeType of the renderer.
-   *
-   * @returns The renderer for the given mimeType, or undefined if the mimeType is unknown.
-   */
-  getFactory(mimeType: string): IRenderMime.IRendererFactory {
-    return this._factories[mimeType];
-  }
-
   private _factories: { [key: string]: IRenderMime.IRendererFactory } = Object.create(null);
   private _mimeTypes: string[] = [];
   private _rankItems: Private.IRankItem[] = [];
@@ -225,6 +259,11 @@ namespace RenderMime {
    */
   export
   interface IOptions {
+    /**
+     * Whether to use the default rendermime factories.  Defaults to `true`.
+     */
+    useDefaultFactories?: boolean;
+
     /**
      * The sanitizer used to sanitize untrusted html inputs.
      *
@@ -298,28 +337,6 @@ namespace RenderMime {
      */
     contents: Contents.IManager;
   }
-
-  /**
-   * Add the default renderer factories to a rendermime instance.
-   */
-  export
-  function addDefaultFactories(rendermime: RenderMime): void {
-    let renderers = [
-      new JavaScriptRendererFactory(),
-      new HTMLRendererFactory(),
-      new MarkdownRendererFactory(),
-      new LatexRendererFactory(),
-      new SVGRendererFactory(),
-      new ImageRendererFactory(),
-      new PDFRendererFactory(),
-      new TextRendererFactory()
-    ];
-    for (let renderer of renderers) {
-      for (let mime of renderer.mimeTypes) {
-        rendermime.addFactory(renderer, mime);
-      }
-    }
-  }
 }
 
 

+ 2 - 2
packages/rendermime/src/widgets.ts

@@ -314,7 +314,7 @@ class RenderedImage extends RenderedCommon {
     let source = Private.getSource(model, this.mimeType);
     let img = this.node.firstChild as HTMLImageElement;
     img.src = `data:${this.mimeType};base64,${source}`;
-    let metadata = model.metadata.get(this.mimeType) as JSONObject;
+    let metadata = model.metadata[this.mimeType] as JSONObject;
     if (metadata) {
       let metaJSON = metadata as JSONObject;
       if (typeof metaJSON['height'] === 'number') {
@@ -470,7 +470,7 @@ namespace Private {
    */
   export
   function getSource(model: IRenderMime.IMimeModel, mimeType: string): string {
-    return String(model.data.get(mimeType));
+    return String(model.data[mimeType]);
   }
 
   /**