Przeglądaj źródła

more rendermime api adjustments

Steven Silvester 7 lat temu
rodzic
commit
582e7e1136

+ 7 - 2
packages/application/src/mimerenderers.ts

@@ -57,8 +57,13 @@ function createRendermimePlugin(item: IRenderMime.IExtension): JupyterLabPlugin<
     autoStart: true,
     activate: (app: JupyterLab, restorer: ILayoutRestorer) => {
       // Add the mime renderer.
-      let index = item.rendererIndex || -1;
-      app.rendermime.addFactory(item.rendererFactory, item.mimeType, index);
+      if (item.rank !== undefined) {
+        app.rendermime.addFactory(
+          item.rendererFactory, item.mimeType, item.rank
+        );
+      } else {
+        app.rendermime.addFactory(item.rendererFactory, item.mimeType);
+      }
 
       // Handle the widget factory.
       if (!item.documentWidgetFactoryOptions) {

+ 2 - 4
packages/cells/src/widget.ts

@@ -753,7 +753,6 @@ class MarkdownCell extends Cell {
       'text/markdown', false
     );
     this._renderer.addClass(MARKDOWN_OUTPUT_CLASS);
-    this._mimeModel = new MimeModel({ trusted: false });
 
     // Throttle the rendering rate of the widget.
     this._monitor = new ActivityMonitor({
@@ -842,16 +841,15 @@ class MarkdownCell extends Cell {
     let text = model && model.value.text || DEFAULT_MARKDOWN_TEXT;
     // Do not re-render if the text has not changed.
     if (text !== this._prevText) {
-      this._mimeModel.data.set('text/markdown', text);
+      let mimeModel = new MimeModel({ data: { 'text/markdown': text }});
       this._prevText = text;
-      return this._renderer.render(this._mimeModel);
+      return this._renderer.renderModel(mimeModel);
     }
     return Promise.resolve(void 0);
   }
 
   private _monitor: ActivityMonitor<any, any> = null;
   private _renderer: IRenderMime.IRendererWidget = null;
-  private _mimeModel: IRenderMime.IMimeModel;
   private _rendered = true;
   private _prevText = '';
   private _ready = new PromiseDelegate<void>();

+ 4 - 6
packages/docregistry/src/default.ts

@@ -429,8 +429,6 @@ class MimeRenderer extends Widget implements DocumentRegistry.IReadyWidget {
     this._renderer = rendermime.createRenderer(this._mimeType, false);
     layout.addWidget(this._renderer);
 
-    this._mimeModel = new MimeModel({ trusted: false });
-
     context.pathChanged.connect(this._onPathChanged, this);
 
     this._context.ready.then(() => {
@@ -498,12 +496,13 @@ class MimeRenderer extends Widget implements DocumentRegistry.IReadyWidget {
   private _render(): Promise<void> {
     let context = this._context;
     let model = context.model;
+    let mimeModel = new MimeModel();
     if (this._dataType === 'string') {
-      this._mimeModel.data.set(this._mimeType, model.toString());
+      mimeModel.data.set(this._mimeType, model.toString());
     } else {
-      this._mimeModel.data.set(this._mimeType, model.toJSON());
+      mimeModel.data.set(this._mimeType, model.toJSON());
     }
-    return this._renderer.render(this._mimeModel);
+    return this._renderer.renderModel(mimeModel);
   }
 
   /**
@@ -516,7 +515,6 @@ class MimeRenderer extends Widget implements DocumentRegistry.IReadyWidget {
   private _context: DocumentRegistry.Context = null;
   private _monitor: ActivityMonitor<any, any> = null;
   private _renderer: IRenderMime.IRendererWidget;
-  private _mimeModel: IRenderMime.IMimeModel;
   private _mimeType: string;
   private _ready = new PromiseDelegate<void>();
   private _dataType: 'string' | 'json';

+ 1 - 1
packages/inspector/src/handler.ts

@@ -190,7 +190,7 @@ class InspectionHandler implements IDisposable, IInspector.IInspectable {
 
       const mimeType = this._rendermime.preferredMimeType(model, trusted);
       let widget = this._rendermime.createRenderer(mimeType, trusted);
-      widget.render(model);
+      widget.renderModel(model);
       update.content = widget;
       this._inspected.emit(update);
     });

+ 1 - 1
packages/outputarea/src/widget.ts

@@ -416,7 +416,7 @@ class OutputArea extends Widget {
 
     let mimeType = this.rendermime.preferredMimeType(model, model.trusted);
     let output = this.rendermime.createRenderer(mimeType, model.trusted);
-    output.render(model);
+    output.renderModel(model);
     output.addClass(OUTPUT_AREA_OUTPUT_CLASS);
     panel.addWidget(output);
 

+ 3 - 3
packages/rendermime-interfaces/src/index.ts

@@ -154,9 +154,9 @@ namespace IRenderMime {
     rendererFactory: IRendererFactory;
 
     /**
-     * The index passed to `RenderMime.addRenderer`.
+     * The rank passed to `RenderMime.addFactory`.
      */
-    rendererIndex?: number;
+    rank?: number;
 
     /**
      * The timeout after user activity to re-render the data.
@@ -204,7 +204,7 @@ namespace IRenderMime {
     /**
      * Render a mime model.
      */
-    render(model: IMimeModel): Promise<void>;
+    renderModel(model: IMimeModel): Promise<void>;
   }
 
   /**

+ 0 - 11
packages/rendermime/src/mimemodel.ts

@@ -19,7 +19,6 @@ class MimeModel implements IRenderMime.IMimeModel {
    * Construct a new mime model.
    */
   constructor(options: MimeModel.IOptions = {}) {
-    this.trusted = !!options.trusted;
     this.data = new MimeModel.Bundle(options.data || {});
     this.metadata = new MimeModel.Bundle(options.metadata || {});
   }
@@ -33,11 +32,6 @@ class MimeModel implements IRenderMime.IMimeModel {
    * The metadata associated with the model.
    */
   readonly metadata: IRenderMime.IBundle;
-
-  /**
-   * Whether the model is trusted.
-   */
-  readonly trusted: boolean;
 }
 
 
@@ -56,11 +50,6 @@ namespace MimeModel {
      */
     data?: JSONObject;
 
-    /**
-     * Whether the output is trusted.  The default is false.
-     */
-    trusted?: boolean;
-
     /**
      * The initial metadata.
      */

+ 3 - 4
packages/rendermime/src/outputmodel.ts

@@ -92,8 +92,8 @@ class OutputModel implements IOutputModel {
    * Construct a new output model.
    */
   constructor(options: IOutputModel.IOptions) {
-    let { trusted, data, metadata } = Private.getBundleOptions(options);
-    this.trusted = trusted;
+    let { data, metadata } = Private.getBundleOptions(options);
+    this.trusted = !!options.trusted;
     this.data = new ObservableJSON({ values: data });
     this.metadata = new ObservableJSON({ values: metadata });
     // Make a copy of the data.
@@ -255,8 +255,7 @@ namespace OutputModel {
   function getBundleOptions(options: IOutputModel.IOptions): MimeModel.IOptions {
     let data = getData(options.value);
     let metadata = getMetadata(options.value);
-    let trusted = !!options.trusted;
-    return { data, trusted, metadata };
+    return { data, metadata };
   }
 
   /**

+ 47 - 24
packages/rendermime/src/rendermime.ts

@@ -75,7 +75,7 @@ class RenderMime {
    * The ordered list of mimeTypes.
    */
   get mimeTypes(): ReadonlyArray<string> {
-    return this._order;
+    return this._mimeTypes;
   }
 
   /**
@@ -114,11 +114,11 @@ class RenderMime {
    *
    * #### Notes
    * The mimeTypes in the model are checked in preference order
-   * until a renderer returns `true` for `.canRender`.
+   * until a renderer returns `true` for `.canCreateRenderer`.
    */
   preferredMimeType(model: IRenderMime.IMimeModel, trusted: boolean): string {
     let sanitizer = this.sanitizer;
-    return find(this._order, mimeType => {
+    return find(this._mimeTypes, mimeType => {
       if (model.data.has(mimeType)) {
         let options = { mimeType, sanitizer, trusted };
         let renderer = this._factories[mimeType];
@@ -147,8 +147,8 @@ class RenderMime {
       sanitizer: this.sanitizer,
       linkHandler: this._handler
     });
-    each(this._order, mimeType => {
-      rendermime.addFactory(this._factories[mimeType], mimeType, -1);
+    each(this._mimeTypes, mimeType => {
+      rendermime.addFactory(this._factories[mimeType], mimeType);
     });
     return rendermime;
   }
@@ -160,28 +160,19 @@ class RenderMime {
    *
    * @param mimeType - The renderer mimeType.
    *
-   * @param index - The optional order index.  Defaults to the last index.
+   * @param rank - The rank of the renderer.  Defaults to 100.
    *
    * #### Notes
-   * Negative indices count from the end, so -1 adds the factory to the end
-   * of the list.
    * The renderer will replace an existing renderer for the given
    * mimeType.
    */
-  addFactory(factory: IRenderMime.IRendererFactory, mimeType: string, index = -1): void {
-    let orig = ArrayExt.removeFirstOf(this._order, mimeType);
-    if (orig !== -1 && orig < index) {
-      index -= 1;
-    }
-    this._factories[mimeType] = factory;
-    if (index < 0) {
-      if (index === -1) {
-        index = this._order.length;
-      } else {
-        index += 1;
-      }
-    }
-    ArrayExt.insert(this._order, index, mimeType);
+  addFactory(factory: IRenderMime.IRendererFactory, mimeType: string, rank = 100): void {
+    let rankItem = { mimeType, rank };
+    let index = ArrayExt.upperBound(
+      this._rankItems, rankItem, Private.itemCmp
+    );
+    ArrayExt.insert(this._rankItems, index, rankItem);
+    ArrayExt.insert(this._mimeTypes, index, mimeType);
   }
 
   /**
@@ -191,7 +182,8 @@ class RenderMime {
    */
   removeFactory(mimeType: string): void {
     delete this._factories[mimeType];
-    ArrayExt.removeFirstOf(this._order, mimeType);
+    let index = ArrayExt.removeFirstOf(this._mimeTypes, mimeType);
+    ArrayExt.removeAt(this._rankItems, index);
   }
 
   /**
@@ -206,7 +198,8 @@ class RenderMime {
   }
 
   private _factories: { [key: string]: IRenderMime.IRendererFactory } = Object.create(null);
-  private _order: string[] = [];
+  private _mimeTypes: string[] = [];
+  private _rankItems: Private.IRankItem[] = [];
   private _resolver: IRenderMime.IResolver | null;
   private _handler: IRenderMime.ILinkHandler | null;
 }
@@ -318,3 +311,33 @@ namespace RenderMime {
     }
   }
 }
+
+
+/**
+ * A namespace for module private data.
+ */
+namespace Private {
+  /**
+   * An object which holds a menu and its sort rank.
+   */
+  export
+  interface IRankItem {
+    /**
+     * The mimetype for the item.
+     */
+    mimeType: string;
+
+    /**
+     * The sort rank of the menu.
+     */
+    rank: number;
+  }
+
+  /**
+   * A comparator function for menu rank items.
+   */
+  export
+  function itemCmp(first: IRankItem, second: IRankItem): number {
+    return first.rank - second.rank;
+  }
+}

+ 21 - 14
packages/rendermime/src/widgets.ts

@@ -131,7 +131,7 @@ abstract class RenderedCommon extends Widget implements IRenderMime.IRendererWid
   /**
    * Render a mime model.
    */
-  abstract render(model: IRenderMime.IMimeModel): Promise<void>;
+  abstract renderModel(model: IRenderMime.IMimeModel): Promise<void>;
 }
 
 
@@ -164,12 +164,12 @@ class RenderedHTML extends RenderedHTMLCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
     if (!this.trusted) {
       source = this.sanitizer.sanitize(source);
     }
-    Private.appendHtml(this.node, source);
+    Private.setHtml(this.node, source);
     if (this.resolver) {
       return Private.handleUrls(
         this.node, this.resolver, this.linkHandler
@@ -213,7 +213,7 @@ class RenderedMarkdown extends RenderedHTMLCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     return new Promise<void>((resolve, reject) => {
       let source = Private.getSource(model, this.mimeType);
       let parts = removeMath(source);
@@ -227,7 +227,7 @@ class RenderedMarkdown extends RenderedHTMLCommon {
         if (!this.trusted) {
           content = this.sanitizer.sanitize(content);
         }
-        Private.appendHtml(this.node, content);
+        Private.setHtml(this.node, content);
         Private.headerAnchors(this.node);
         this.fit();
         if (this.resolver) {
@@ -274,7 +274,7 @@ class RenderedLatex extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
     this.node.textContent = source;
     if (this.isAttached) {
@@ -310,7 +310,7 @@ class RenderedImage extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
     let img = this.node.firstChild as HTMLImageElement;
     img.src = `data:${this.mimeType};base64,${source}`;
@@ -350,10 +350,13 @@ class RenderedText extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
     let data = escape_for_html(source);
     let pre = this.node.firstChild as HTMLPreElement;
+    while (pre.firstChild) {
+      pre.removeChild(pre.firstChild);
+    }
     pre.innerHTML = ansi_to_html(data, {use_classes: true});
     return Promise.resolve(void 0);
   }
@@ -379,7 +382,7 @@ class RenderedJavaScript extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let s = this.node.firstChild as HTMLScriptElement;
     let source = Private.getSource(model, this.mimeType);
     s.textContent = source;
@@ -404,9 +407,9 @@ class RenderedSVG extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
-    this.node.innerHTML = source;
+    Private.setHtml(this.node, source);
     let svgElement = this.node.getElementsByTagName('svg')[0];
     if (!svgElement) {
       let msg = 'SVGRender: Error: Failed to create <svg> element';
@@ -449,7 +452,7 @@ class RenderedPDF extends RenderedCommon {
   /**
    * Render a mime model.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     let source = Private.getSource(model, this.mimeType);
     let a = this.node.firstChild as HTMLAnchorElement;
     a.href = `data:application/pdf;base64,${source}`;
@@ -471,10 +474,14 @@ namespace Private {
   }
 
   /**
-   * Append trusted html to a node.
+   * Set trusted html to a node.
    */
   export
-  function appendHtml(node: HTMLElement, html: string): void {
+  function setHtml(node: HTMLElement, html: string): void {
+    // Remove any existing child nodes.
+    while (node.firstChild) {
+      node.removeChild(node.firstChild);
+    }
     try {
       let range = document.createRange();
       node.appendChild(range.createContextualFragment(html));

+ 1 - 1
packages/tooltip/src/widget.ts

@@ -80,7 +80,7 @@ class Tooltip extends Widget {
     let mimeType = this._rendermime.preferredMimeType(model, true);
     if (mimeType) {
       this._content = this._rendermime.createRenderer(mimeType, true);
-      this._content.render(model);
+      this._content.renderModel(model);
       (this.layout as PanelLayout).addWidget(this._content);
     }
   }

+ 3 - 3
packages/vega/src/index.ts

@@ -79,7 +79,7 @@ class RenderedVega extends Widget implements IRenderMime.IRendererWidget {
   /**
    * Render Vega/Vega-Lite into this widget's node.
    */
-  render(model: IRenderMime.IMimeModel): Promise<void> {
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
 
     let data = model.data.get(this._mimeType) as JSONObject;
 
@@ -145,7 +145,7 @@ const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [
   {
     mimeType: VEGA_MIME_TYPE,
     rendererFactory,
-    rendererIndex: 0,
+    rank: 0,
     dataType: 'json',
     documentWidgetFactoryOptions: {
       name: 'Vega',
@@ -158,7 +158,7 @@ const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [
   {
     mimeType: VEGALITE_MIME_TYPE,
     rendererFactory,
-    rendererIndex: 0,
+    rank: 0,
     dataType: 'json',
     documentWidgetFactoryOptions: {
       name: 'Vega-Lite',