Browse Source

Merge pull request #6513 from ian-r-rose/no-append-on-rerender

Don't append content in rendered output upon rerendering.
Steven Silvester 5 years ago
parent
commit
8d361270e9
2 changed files with 54 additions and 0 deletions
  1. 11 0
      packages/rendermime/src/widgets.ts
  2. 43 0
      tests/test-rendermime/src/factories.spec.ts

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

@@ -63,10 +63,21 @@ export abstract class RenderedCommon extends Widget
    * @param model - The mime model to render.
    *
    * @returns A promise which resolves when rendering is complete.
+   *
+   * #### Notes
+   * If the DOM node for this widget already has content, it is emptied
+   * before rendering. Subclasses that do not want this behavior
+   * (if, for instance, they are using DOM diffing), should override
+   * this method and not call `super.renderModel()`.
    */
   async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
     // TODO compare model against old model for early bail?
 
+    // Empty any existing content in the node from previous renders
+    while (this.node.firstChild) {
+      this.node.removeChild(this.node.firstChild);
+    }
+
     // Toggle the trusted class on the widget.
     this.toggleClass('jp-mod-trusted', model.trusted);
 

+ 43 - 0
tests/test-rendermime/src/factories.spec.ts

@@ -66,6 +66,16 @@ describe('rendermime/factories', () => {
         expect(w.node.innerHTML).to.equal('<pre>x = 2 ** a</pre>');
       });
 
+      it('should be re-renderable', async () => {
+        const f = textRendererFactory;
+        const mimeType = 'text/plain';
+        const model = createModel(mimeType, 'x = 2 ** a');
+        const w = f.createRenderer({ mimeType, ...defaultOptions });
+        await w.renderModel(model);
+        await w.renderModel(model);
+        expect(w.node.innerHTML).to.equal('<pre>x = 2 ** a</pre>');
+      });
+
       it('should output the correct HTML with ansi colors', async () => {
         const f = textRendererFactory;
         const source = 'There is no text but \x1b[01;41;32mtext\x1b[00m.\nWoo.';
@@ -116,6 +126,17 @@ describe('rendermime/factories', () => {
         await w.renderModel(model);
         expect(w.node.textContent).to.equal(source);
       });
+
+      it('should be re-renderable', async () => {
+        const source = 'sumlimits_{i=0}^{infty} \frac{1}{n^2}';
+        const f = latexRendererFactory;
+        const mimeType = 'text/latex';
+        const model = createModel(mimeType, source);
+        const w = f.createRenderer({ mimeType, ...defaultOptions });
+        await w.renderModel(model);
+        await w.renderModel(model);
+        expect(w.node.textContent).to.equal(source);
+      });
     });
   });
 
@@ -174,6 +195,17 @@ describe('rendermime/factories', () => {
         expect(w.node.innerHTML).to.equal(source);
       });
 
+      it('it should be re-renderable', async () => {
+        const f = markdownRendererFactory;
+        const source = '<p>hello</p>';
+        const mimeType = 'text/markdown';
+        const model = createModel(mimeType, source);
+        const w = f.createRenderer({ mimeType, ...defaultOptions });
+        await w.renderModel(model);
+        await w.renderModel(model);
+        expect(w.node.innerHTML).to.equal(source);
+      });
+
       it('should add header anchors', async () => {
         const source = require('../../../examples/filebrowser/sample.md')
           .default as string;
@@ -229,6 +261,17 @@ describe('rendermime/factories', () => {
         expect(w.node.innerHTML).to.equal('<h1>This is great</h1>');
       });
 
+      it('should be re-renderable', async () => {
+        const f = htmlRendererFactory;
+        const source = '<h1>This is great</h1>';
+        const mimeType = 'text/html';
+        const model = createModel(mimeType, source);
+        const w = f.createRenderer({ mimeType, ...defaultOptions });
+        await w.renderModel(model);
+        await w.renderModel(model);
+        expect(w.node.innerHTML).to.equal('<h1>This is great</h1>');
+      });
+
       // TODO we are disabling script execution for now.
       it.skip('should execute a script tag when attached', () => {
         const source = '<script>window.y=3;</script>';