JSFiddle to Images Converter

This converts code snippets from JS fiddles into images via canvas. The point? To end up with images that you can include in Medium articles that don't trigger the DNT warnings.

by khamer

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/canvas2image.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/gruvbox-dark.min.css">
<main>
    <section>
        <h2>What is this?</h2>
        <p>
            This takes the URL of a JSFiddle and generates some images of your code to use in blog posts, articles, or whatever you have in mind where the typical embed wouldn't work. Feel free to customize this and use it how you see fit.
        </p>
        <input type="text" v-model="fiddleURL" placeholder="fiddle URL">
        <button @click="createImages">make images</button>
    </section>
    <div v-if="!rendered" class="hljs" ref="combined">
        <div v-if="hlhtml" ref="html">
            <h2>&lt;!-- HTML --&gt;</h2>
            <pre><code class="hljs" v-html="hlhtml && hlhtml.value"></code></pre>
        </div>
        <div v-if="hljs" ref="js">
            <h2>// Javascript</h2>
            <pre><code class="hljs" v-html="hljs && hljs.value"></code></pre>
        </div>
        <div v-if="hlcss" ref="css">
            <h2>// CSS</h2>
            <pre><code class="hljs" v-html="hlcss && hlcss.value"></code></pre>
        </div>
    </div>

    <div v-else>
        <p>
            Below are your images. Right click them and choose Save As if you'd like.
        </p>
    </div>
    <div ref="canvases"></div>
</main>

SCSS

/* You might want to change the values in this block: */
code {
  font-family: monospace;
  font-size: 11pt;
  padding: 1rem 1.618rem !important;
  width: 700px;
}
.hljs {
  width: 700px;
  padding: 0;

  h2 {
    font-weight: bold;
    font-family: monospace;
    background: #242424; 
  }
}
/* Probably don't need to change anything below this, but you can if you want. */


html, body {
  font-family: arial;
}

input {
  width: 100%;
}

pre {
  margin: 0;
}


.hljs h2 {
  font-size: inherit;
  padding: .5rem;
  margin: 0;
}

JavaScript

var decodeHtml = function(html) {
    var txt = document.createElement("textarea");
    txt.innerHTML = html;
    return txt.value;
}

new Vue({
    el: 'main',
    data: {
        js: null,
        html: null,
        css: null,
        canvas: null,
        fiddleURL: null,
        rendered: false,
    },

    watch: {
        fiddle() {
            for (let lang of['html', 'js', 'css']) {
                axios.get(`/${this.fiddle}/embedded/${lang}`)
                    .then(response => {
                        let d = (new DOMParser).parseFromString(response.data, 'text/html');
                        this[lang] = d.querySelector('#tabs pre:first-child').innerHTML;
                    });
            }
        }
    },

    computed: {
        hljs() {
                return this.js && hljs.highlight('javascript', decodeHtml(this.js));
            },

            hlcss() {
                return this.css && hljs.highlight('css', decodeHtml(this.css));
            },

            hlhtml() {
                return this.html && hljs.highlight('html', decodeHtml(this.html));
            },

            fiddle() {
                let rx = /^(https?:\/\/jsfiddle.net\/|\/)?(.*?)\/?(embedded\/?(js|css|html|result)?)?$/i;
                return this.fiddleURL && this.fiddleURL.replace(rx, '$2');
            }
    },

    methods: {
        createImages() {
            this.rendered = false;
            this.$nextTick(() => {
                let el = this.$refs.canvases;
                while (el.firstChild) {
                    el.removeChild(el.firstChild);
                }
                html2canvas(this.$refs.combined).then(canvas => {
                    el.appendChild(canvas);
                    this.rendered = true;
                })
                for (let lang of['html', 'js', 'css']) {
                    html2canvas(this.$refs[lang]).then(canvas => {
                        el.appendChild(canvas);
                    });
                }
           ...