gridsome / gridsome

⚡️ The Jamstack framework for Vue.js
https://gridsome.org
MIT License
8.55k stars 489 forks source link

Markdown <script> tags not processed #532

Open fullpwemium opened 5 years ago

fullpwemium commented 5 years ago

Description

Not able to embed plot.ly plots via markdown.

Steps to reproduce

<div id="7979e646-13e6-4f44-8d32-d8effc3816df" class="plotly-graph-div"></div>
<script>window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL="https://plot.ly";Plotly.newPlot("7979e646-13e6-4f44-8d32-d8effc3816df", [{"x": [1, 2, 3], "y": [3, 1, 6]}], {}, {"showLink": false, "linkText": ""})</script>

Include following in main.js export default function:

  head.script.push({
    src: 'https://cdn.plot.ly/plotly-latest.min.js',
    body: false
  })</script>

Expected result

A plotly plot to be inserted into the div

Actual result

Nothing is output. The script is included in head, the div and script tags appear in the DOM, but the script tag is not processed. If I copy the contents of the script tag into the chrome console, the plot appears.

Environment


Libs:
   "@gridsome/cli": "^0.2.1",
    "@gridsome/plugin-google-analytics": "^0.1.0",
    "@gridsome/source-filesystem": "^0.5.0",
    "@gridsome/transformer-remark": "^0.3.2",
    "gridsome": "^0.6.5",
    "gridsome-plugin-remark-shiki": "^0.3.0",
    "gridsome-plugin-remark-twitter": "^0.1.2",
    "gridsome-plugin-remark-youtube": "^1.0.1",
    "remark-html-katex": "^1.2.0",
    "remark-math": "^1.0.6",
    "vue-katex": "^0.2.0"


Browser:
- [x] Chrome (desktop) version 75
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX

hjvedvik commented 5 years ago

The browser won't execute script tags after the DOM is loaded, unfortunately :) You need to somehow run eval or use jQuery or equivalent to insert the markup instead. But a better approach would probably be to do something like this in the mounted hook:

this.$refs.div
  .querySelectorAll('.plotly-graph-div')
  .forEach(el => Plotly.newPlot(el.id, ...))
fullpwemium commented 5 years ago
this.$refs.div
  .querySelectorAll('.plotly-graph-div')
  .forEach(el => Plotly.newPlot(el.id, ...))

thank you for getting back to me! I have the following in my Blog template:

  mounted() {
    this.$refs.div
    .querySelectorAll('.plotly-graph-div')
    .forEach(el => Plotly.newPlot(el.id, ...))
    }   
}

This doesn't work because I suspect you gave an example of how to do it, i.e. the ellipses, but my javascript isn't that good! Do you by any chance have a working example? I understand if this is asking too much

u12206050 commented 5 years ago

Here is a generic all in one function you can use to insert html (script included) and have it execute any scripts within. Either add this function on the page where you will use it as a helper:

<template>
  <div ref="snippet_container"></div>
</template>
…

<script>
let htmlEl = null
export default {
…
 methods: {
    insertSnippet(htmlSnippet) {
      if (htmlEl) return // **Remove this if you need**
      const el = this.$refs.snippet_container
      htmlEl = document.createElement('div')
      htmlEl.classList.add('html-snippet')
      htmlEl.innerHTML = htmlSnippet
      el.appendChild(htmlEl)
      const scriptsTags = htmlEl.getElementsByTagName('script')
      // This is necessary otherwise the scripts tags are not going to be evaluated
      for (let i = 0; i < scriptsTags.length; i++) {
        let parentNode = scriptsTags[i].parentNode
        let newScriptTag = document.createElement('script')
        newScriptTag.type = 'text/javascript'
        newScriptTag.text = scriptsTags[i].text
        parentNode.removeChild(scriptsTags[i])
        parentNode.appendChild(newScriptTag)
      }
    }
hjvedvik commented 5 years ago

The insertSnippet() method in @u12206050's comment might be easier to use. But here is also a more detailed example of what I wrote earlier. I haven't been able to test if it works..

<template>
  <div>
    <div ref="content" v-html="$page.post.content" />
  </div>
</template>

<page-query>
query ($id: String!) {
  post(id: $id) {
    content
  }
}
</page-query>

<script>
export default {
  mounted () {
    this.$refs.content // or just this.$el
      .querySelectorAll('.plotly-graph-div')
      .forEach(el => {
        Plotly.newPlot(el.id, [{ x: [1, 2, 3], y: [3, 1, 6] }], {}, { showLink: false, linkText: '' })
      })
  }
}
</script>