Quellcode durchsuchen

Leave the url resolving to the renderer

Steven Silvester vor 8 Jahren
Ursprung
Commit
06edd1cec4

+ 10 - 16
src/docmanager/context.ts

@@ -191,11 +191,10 @@ class Context implements IDocumentContext<IDocumentModel> {
   }
 
   /**
-   * Traverse the DOM hierarchy of a node, translating
-   * relative URLs.
+   * Resolve a url to a correct server path.
    */
-  resolveUrls(node: HTMLElement): void {
-    return this._manager.resolveUrls(this._id, node);
+  resolveUrl(url: string): string {
+    return this._manager.resolveUrl(this._id, url);
   }
 
   /**
@@ -536,21 +535,16 @@ class ContextManager implements IDisposable {
   }
 
   /**
-   * Traverse the DOM hierarchy of a node, translating
-   * relative URLs.
+   * Resolve a relative url to a correct server path.
    */
-  resolveUrls(id: string, node: HTMLElement): void {
+  resolveUrl(id: string, url: string): string {
+    if (url.indexOf('./')) {
+      return url;
+    }
     let contextEx = this._contexts[id];
     let cwd = ContentsManager.dirname(contextEx.path);
-    let imgs = node.getElementsByTagName('img');
-    for (let i = 0; i < imgs.length; i++) {
-      let img = imgs[i];
-      let source = img.getAttribute('src');
-      if (source.indexOf('./') !== -1) {
-        let path = ContentsManager.getAbsolutePath(source, cwd);
-        img.src = this._manager.contents.getDownloadUrl(path);
-      }
-    }
+    let path = ContentsManager.getAbsolutePath(url, cwd);
+    return this._manager.contents.getDownloadUrl(path);
   }
 
   /**

+ 2 - 3
src/docregistry/interfaces.ts

@@ -206,10 +206,9 @@ export interface IDocumentContext<T extends IDocumentModel> extends IDisposable
   listSessions(): Promise<ISession.IModel[]>;
 
   /**
-   * Traverse the DOM hierarchy of a node, translating
-   * relative URLs.
+   * Resolve a url to a correct server path.
    */
-  resolveUrls(node: HTMLElement): void;
+  resolveUrl(url: string): string;
 
   /**
    * Add a sibling widget to the document manager.

+ 9 - 4
src/markdownwidget/widget.ts

@@ -46,7 +46,7 @@ class MarkdownWidget extends Widget {
     this.layout = new PanelLayout();
     this.title.text = context.path.split('/').pop();
     this._renderer = new MarkdownRenderer();
-    this._model = context.model;
+    this._context = context;
 
     context.pathChanged.connect((c, path) => {
       this.title.text = path.split('/').pop();
@@ -69,9 +69,14 @@ class MarkdownWidget extends Widget {
    */
   protected onUpdateRequest(msg: Message): void {
     let renderer = this._renderer;
-    let model = this._model;
+    let context = this._context;
+    let model = context.model;
     let layout = this.layout as PanelLayout;
-    let widget = renderer.render('text/markdown', model.toString());
+    let widget = renderer.render({
+      mimetype: 'text/markdown',
+      source: model.toString(),
+      resolver: context
+    });
     if (layout.childCount()) {
       layout.childAt(0).dispose();
     }
@@ -79,7 +84,7 @@ class MarkdownWidget extends Widget {
   }
 
   private _renderer: MarkdownRenderer = null;
-  private _model: IDocumentModel = null;
+  private _context: IDocumentContext<IDocumentModel> = null;
 }
 
 

+ 80 - 34
src/renderers/index.ts

@@ -163,15 +163,17 @@ class HTMLRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
-    return new HTMLWidget(data);
+  render(options: RenderMime.IRenderOptions): Widget {
+    let w = new HTMLWidget(options.source);
+    resolveUrls(w.node, options.resolver);
+    return w;
   }
 }
 
@@ -203,17 +205,17 @@ class ImageRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
+  render(options: RenderMime.IRenderOptions): Widget {
     let w = new Widget();
     let img = document.createElement('img');
-    img.src = `data:${mimetype};base64,${data}`;
+    img.src = `data:${options.mimetype};base64,${options.source}`;
     w.node.appendChild(img);
     w.addClass(RENDERED_CLASS);
     return w;
@@ -248,17 +250,17 @@ class TextRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    data = escape_for_html(data);
+  transform(options: RenderMime.IRenderOptions): string {
+    let data = escape_for_html(options.source);
     return `<pre>${ansi_to_html(data)}</pre>`;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
+  render(options: RenderMime.IRenderOptions): Widget {
     let w = new Widget();
-    w.node.innerHTML = data;
+    w.node.innerHTML = options.source;
     w.addClass(RENDERED_CLASS);
     return w;
   }
@@ -292,18 +294,18 @@ class JavascriptRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
+  render(options: RenderMime.IRenderOptions): Widget {
     let w = new Widget();
     let s = document.createElement('script');
-    s.type = mimetype;
-    s.textContent = data;
+    s.type = options.mimetype;
+    s.textContent = options.source;
     w.node.appendChild(s);
     w.addClass(RENDERED_CLASS);
     return w;
@@ -338,20 +340,21 @@ class SVGRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
+  render(options: RenderMime.IRenderOptions): Widget {
     let w = new Widget();
-    w.node.innerHTML = data;
+    w.node.innerHTML = options.source;
     let svgElement = w.node.getElementsByTagName('svg')[0];
     if (!svgElement) {
       throw new Error('SVGRender: Error: Failed to create <svg> element');
     }
+    resolveUrls(w.node, options.resolver);
     w.addClass(RENDERED_CLASS);
     return w;
   }
@@ -385,19 +388,19 @@ class PDFRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
+  render(options: RenderMime.IRenderOptions): Widget {
     let w = new Widget();
     let a = document.createElement('a');
     a.target = '_blank';
     a.textContent = 'View PDF';
-    a.href = 'data:application/pdf;base64,' + data;
+    a.href = 'data:application/pdf;base64,' + options.source;
     w.node.appendChild(a);
     w.addClass(RENDERED_CLASS);
     return w;
@@ -432,15 +435,15 @@ class LatexRenderer implements RenderMime.IRenderer  {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): string {
-    return data;
+  transform(options: RenderMime.IRenderOptions): string {
+    return options.source;
   }
 
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
-    return new LatexWidget(data);
+  render(options: RenderMime.IRenderOptions): Widget {
+    return new LatexWidget(options.source);
   }
 }
 
@@ -472,10 +475,29 @@ class MarkdownRenderer implements RenderMime.IRenderer {
   /**
    * Transform the input bundle.
    */
-  transform(mimetype: string, data: string): Promise<string> {
-    let parts = removeMath(data);
+  transform(options: RenderMime.IRenderOptions): Promise<string> {
+    let parts = removeMath(options.source);
+    let renderer = new marked.Renderer();
+    renderer.link = (href: string, title: string, text: string) => {
+      href = options.resolver.resolveUrl(href);
+      let out = '<a href="' + href + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += '>' + text + '</a>';
+      return out;
+    };
+    renderer.image = (href: string, title: string, text: string) => {
+      href = options.resolver.resolveUrl(href);
+      let out = '<img src="' + href + '" alt="' + text + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += '>';
+      return out;
+    };
     return new Promise<string>((resolve, reject) => {
-      marked(parts['text'], (err, content) => {
+      marked(parts['text'], { renderer }, (err, content) => {
         if (err) {
           reject(err);
         }
@@ -487,7 +509,31 @@ class MarkdownRenderer implements RenderMime.IRenderer {
   /**
    * Render the transformed mime bundle.
    */
-  render(mimetype: string, data: string): Widget {
-    return new HTMLWidget(data);
+  render(options: RenderMime.IRenderOptions): Widget {
+    return new HTMLWidget(options.source);
+  }
+}
+
+
+/**
+ * Resolve the relative urls in the image and anchor tags of a node tree.
+ *
+ * @param node - The head html element.
+ *
+ * @param resolver - A url resolver.
+ */
+export
+function resolveUrls(node: HTMLElement, resolver: RenderMime.IResolver): void {
+  let imgs = node.getElementsByTagName('img');
+  for (let i = 0; i < imgs.length; i++) {
+    let img = imgs[i];
+    let source = img.getAttribute('src');
+    img.src = resolver.resolveUrl(source);
+  }
+  let anchors = node.getElementsByTagName('a');
+  for (let i = 0; i < anchors.length; i++) {
+    let anchor = anchors[i];
+    let href = anchor.getAttribute('href');
+    anchor.href = resolver.resolveUrl(href);
   }
 }

+ 37 - 16
src/rendermime/index.ts

@@ -57,18 +57,19 @@ class RenderMime {
     if (!mimetype) {
       return Promise.resolve(void 0);
     }
+    let options = {
+      mimetype,
+      source: bundle[mimetype],
+      resolver: this._resolver
+    };
     let renderer = this._renderers[mimetype];
-    let transform = renderer.transform(mimetype, bundle[mimetype]);
+    let transform = renderer.transform(options);
     return Promise.resolve(transform).then(content => {
       if (!trusted && renderer.sanitizable(mimetype)) {
         content = this._sanitizer.sanitize(content);
       }
-      let widget = renderer.render(content, content);
-      let resolver = this.resolver;
-      if (resolver) {
-        resolver.resolveUrls(widget.node);
-      }
-      return widget;
+      options.source = content;
+      return renderer.render(options);
     });
   }
 
@@ -227,21 +228,43 @@ namespace RenderMime {
 
     /**
      * Transform the input bundle.
+     *
+     * @param options - The options used for transforming.
+     *
      */
-    transform(mimetype: string, data: string): string | Promise<string>;
+    transform(options: IRenderOptions): string | Promise<string>;
 
     /**
      * Render the transformed mime bundle.
      *
-     * @param mimetype - the mimetype for the data
-     *
-     * @param data - the data to render.
+     * @param options - The options used for rendering.
      *
      * #### Notes
      * It is assumed that the data has been run through [[transform]]
      * and has been sanitized if necessary.
      */
-    render(mimetype: string, data: string): Widget;
+    render(options: IRenderOptions): Widget;
+  }
+
+  /**
+   * The options used to transform or render mime data.
+   */
+  export
+  interface IRenderOptions {
+    /**
+     * The mimetype.
+     */
+    mimetype: string;
+
+    /**
+     * The source data.
+     */
+    source: string;
+
+    /**
+     * The url resolver.
+     */
+    resolver: IResolver;
   }
 
   /**
@@ -250,10 +273,8 @@ namespace RenderMime {
   export
   interface IResolver {
     /**
-     * Traverse the DOM hierarchy of a node, translating
-     * relative URLs.
+     * Resolve a url to a correct server path.
      */
-    resolveUrls(node: HTMLElement): void;
+    resolveUrl(url: string): string;
   }
 }
-