From 62c50d9e236dd9f61c97e02774fc7e1bad4c30f0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 5 Dec 2019 17:41:54 -0500 Subject: [PATCH] avoid redrawing mermaid graphs which have not changed --- www/common/diffMarked.js | 60 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 5817e5ac9..0f92897bc 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -197,7 +197,6 @@ define([ 'APPLET', 'VIDEO', // privacy implications of videos are the same as images 'AUDIO', // same with audio - 'SVG' ]; var unsafeTag = function (info) { /*if (info.node && $(info.node).parents('media-tag').length) { @@ -307,8 +306,39 @@ define([ var Dom = domFromHTML($('
').append($div).html()); $content[0].normalize(); - $content.find('pre.mermaid[data-processed="true"]').remove(); + + var mermaid_source = []; + var mermaid_cache = {}; + + // iterate over the unrendered mermaid inputs, caching their source as you go + $(newDomFixed).find('pre.mermaid').each(function (index, el) { + if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) { + var src = el.childNodes[0].wholeText; + el.setAttribute('mermaid-source', src); + mermaid_source[index] = src; + } + }); + + // iterate over rendered mermaid charts + $content.find('pre.mermaid:not([processed="true"])').each(function (index, el) { + // retrieve the attached source code which it was drawn + var src = el.getAttribute('mermaid-source'); + + // check if that source exists in the set of charts which are about to be rendered + if (mermaid_source.indexOf(src) === -1) { + // if it's not, then you can remove it + if (el.parentNode && el.parentNode.children.length) { + el.parentNode.removeChild(el); + } + } else if (el.childNodes.length === 1 && el.childNodes[0].nodeType !== 3) { + // otherwise, confirm that the content of the rendered chart is not a text node + // and keep a copy of it + mermaid_cache[src] = el.childNodes[0]; + } + }); + var oldDom = domFromHTML($content[0].outerHTML); + var patch = makeDiff(oldDom, Dom, id); if (typeof(patch) === 'string') { throw new Error(patch); @@ -348,8 +378,32 @@ define([ var target = document.getElementById($a.attr('data-href')); if (target) { target.scrollIntoView(); } }); + + // loop over mermaid elements in the rendered content + $content.find('pre.mermaid').each(function (index, el) { + // since you've simply drawn the content that was supplied via markdown + // you can assume that the index of your rendered charts matches that + // of those in the markdown source. + var src = mermaid_source[index]; + el.setAttribute('mermaid-source', src); + var cached = mermaid_cache[src]; + + // check if you had cached a pre-rendered instance of the supplied source + if (typeof(cached) !== 'object') { return; } + + // if there's a cached rendering, empty out the contained source code + // which would otherwise be drawn again. + // apparently this is the fastest way to empty out an element + while (el.firstChild) { el.removeChild(el.firstChild); } //el.innerHTML = ''; + // insert the cached graph + el.appendChild(cached); + // and set a flag indicating that this graph need not be reprocessed + el.setAttribute('data-processed', true); + }); + try { - Mermaid.init(); + // finally, draw any graphs which have changed and were thus not cached + Mermaid.init(undefined, $content.find('pre.mermaid:not([data-processed="true"])')); } catch (e) { console.error(e); } } };