Copy Mermaid graphs as GFM
This commit is contained in:
parent
58a705aaac
commit
288b276077
6 changed files with 131 additions and 14 deletions
|
@ -74,6 +74,18 @@ const gfmRules = {
|
|||
return `![${el.dataset.title}](${el.getAttribute('src')})`;
|
||||
},
|
||||
},
|
||||
MermaidFilter: {
|
||||
'svg.mermaid'(el, text) {
|
||||
const sourceEl = el.querySelector('text.source');
|
||||
if (!sourceEl) return false;
|
||||
|
||||
return `\`\`\`mermaid\n${CopyAsGFM.nodeToGFM(sourceEl)}\n\`\`\``;
|
||||
},
|
||||
'svg.mermaid style, svg.mermaid g'(el, text) {
|
||||
// We don't want to include the content of these elements in the copied text.
|
||||
return '';
|
||||
},
|
||||
},
|
||||
MathFilter: {
|
||||
'pre.code.math[data-math-style=display]'(el, text) {
|
||||
return `\`\`\`math\n${text.trim()}\n\`\`\``;
|
||||
|
|
|
@ -24,7 +24,25 @@ export default function renderMermaid($els) {
|
|||
});
|
||||
|
||||
$els.each((i, el) => {
|
||||
mermaid.init(undefined, el);
|
||||
const source = el.textContent;
|
||||
|
||||
mermaid.init(undefined, el, (id) => {
|
||||
const svg = document.getElementById(id);
|
||||
|
||||
svg.classList.add('mermaid');
|
||||
|
||||
// pre > code > svg
|
||||
svg.closest('pre').replaceWith(svg);
|
||||
|
||||
// We need to add the original source into the DOM to allow Copy-as-GFM
|
||||
// to access it.
|
||||
const sourceEl = document.createElement('text');
|
||||
sourceEl.classList.add('source');
|
||||
sourceEl.setAttribute('display', 'none');
|
||||
sourceEl.textContent = source;
|
||||
|
||||
svg.appendChild(sourceEl);
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
Flash(`Can't load mermaid module: ${err}`);
|
||||
|
|
|
@ -2,16 +2,7 @@ module Banzai
|
|||
module Filter
|
||||
class MermaidFilter < HTML::Pipeline::Filter
|
||||
def call
|
||||
doc.css('pre[lang="mermaid"]').add_class('mermaid')
|
||||
doc.css('pre[lang="mermaid"]').add_class('js-render-mermaid')
|
||||
|
||||
# The `<code></code>` blocks are added in the lib/banzai/filter/syntax_highlight_filter.rb
|
||||
# We want to keep context and consistency, so we the blocks are added for all filters.
|
||||
# Details: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107/diffs?diff_id=7962900#note_45495859
|
||||
doc.css('pre[lang="mermaid"]').each do |pre|
|
||||
document = pre.at('code')
|
||||
document.replace(document.content)
|
||||
end
|
||||
doc.css('pre[lang="mermaid"] > code').add_class('js-render-mermaid')
|
||||
|
||||
doc
|
||||
end
|
||||
|
|
|
@ -284,6 +284,102 @@ describe 'Copy as GFM', :js do
|
|||
expect(output_gfm.strip).to eq(gfm.strip)
|
||||
end
|
||||
|
||||
verify(
|
||||
'MermaidFilter: mermaid as converted from GFM to HTML',
|
||||
|
||||
<<-GFM.strip_heredoc
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
```
|
||||
GFM
|
||||
)
|
||||
|
||||
aggregate_failures('MermaidFilter: mermaid as transformed from HTML to SVG') do
|
||||
gfm = <<-GFM.strip_heredoc
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
```
|
||||
GFM
|
||||
|
||||
html = <<-HTML.strip_heredoc
|
||||
<svg id="mermaidChart1" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 87.234375 174" style="max-width:87.234375px;" class="mermaid">
|
||||
<style>
|
||||
.mermaid {
|
||||
/* Flowchart variables */
|
||||
/* Sequence Diagram variables */
|
||||
/* Gantt chart variables */
|
||||
/** Section styling */
|
||||
/* Grid and axis */
|
||||
/* Today line */
|
||||
/* Task styling */
|
||||
/* Default task */
|
||||
/* Specific task settings for the sections*/
|
||||
/* Active task */
|
||||
/* Completed task */
|
||||
/* Tasks on the critical line */
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<g class="output">
|
||||
<g class="clusters"></g>
|
||||
<g class="edgePaths">
|
||||
<g class="edgePath" style="opacity: 1;">
|
||||
<path class="path" d="M33.6171875,52L33.6171875,77L33.6171875,102" marker-end="url(#arrowhead65)" style="fill:none"></path>
|
||||
<defs>
|
||||
<marker id="arrowhead65" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path>
|
||||
</marker>
|
||||
</defs>
|
||||
</g>
|
||||
</g>
|
||||
<g class="edgeLabels">
|
||||
<g class="edgeLabel" style="opacity: 1;" transform="">
|
||||
<g transform="translate(0,0)" class="label">
|
||||
<foreignObject width="0" height="0">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">
|
||||
<span class="edgeLabel"></span>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="nodes">
|
||||
<g class="node" id="A" transform="translate(33.6171875,36)" style="opacity: 1;">
|
||||
<rect rx="0" ry="0" x="-13.6171875" y="-16" width="27.234375" height="32"></rect>
|
||||
<g class="label" transform="translate(0,0)">
|
||||
<g transform="translate(-3.6171875,-6)">
|
||||
<foreignObject width="7.234375" height="12">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">A</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="node" id="B" transform="translate(33.6171875,118)" style="opacity: 1;">
|
||||
<rect rx="0" ry="0" x="-13.6171875" y="-16" width="27.234375" height="32">
|
||||
</rect>
|
||||
<g class="label" transform="translate(0,0)">
|
||||
<g transform="translate(-3.6171875,-6)">
|
||||
<foreignObject width="7.234375" height="12">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">B</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<text class="source" display="none">graph TD;
|
||||
A-->B;
|
||||
</text>
|
||||
</svg>
|
||||
HTML
|
||||
|
||||
output_gfm = html_to_gfm(html)
|
||||
expect(output_gfm.strip).to eq(gfm.strip)
|
||||
end
|
||||
|
||||
verify(
|
||||
'SanitizationFilter',
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ describe 'GitLab Markdown' do
|
|||
|
||||
it 'parses mermaid code block' do
|
||||
aggregate_failures do
|
||||
expect(doc).to have_selector('pre.code.js-render-mermaid')
|
||||
expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ require 'spec_helper'
|
|||
describe Banzai::Filter::MermaidFilter do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'adds `js-render-mermaid` class to the `pre` tag' do
|
||||
it 'adds `js-render-mermaid` class to the `code` tag' do
|
||||
doc = filter("<pre class='code highlight js-syntax-highlight mermaid' lang='mermaid' v-pre='true'><code>graph TD;\n A-->B;\n</code></pre>")
|
||||
result = doc.xpath('descendant-or-self::pre').first
|
||||
result = doc.css('code').first
|
||||
|
||||
expect(result[:class]).to include('js-render-mermaid')
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue