From f23fbc9e798074f9c0e6103e3511b2b63107925f Mon Sep 17 00:00:00 2001 From: Avi Herman Date: Wed, 12 Feb 2025 19:22:54 -0500 Subject: [PATCH 1/3] added plotly --- background/inject.js | 1 + background/storage.js | 1 + build/package.sh | 1 + build/plotly/build.sh | 14 ++++++++++++ build/plotly/package.json | 12 ++++++++++ content/index.css | 8 ++++++- content/index.js | 11 ++++++++- content/plotly.js | 48 +++++++++++++++++++++++++++++++++++++++ content/scroll.js | 16 ++++++++++++- manifest.chrome.json | 2 +- popup/index.js | 1 + 11 files changed, 111 insertions(+), 4 deletions(-) create mode 100755 build/plotly/build.sh create mode 100644 build/plotly/package.json create mode 100644 content/plotly.js diff --git a/background/inject.js b/background/inject.js index da617b3..fb8b7f0 100644 --- a/background/inject.js +++ b/background/inject.js @@ -34,6 +34,7 @@ md.inject = ({storage: {state}}) => (id) => { state.content.syntax && ['/vendor/prism.min.js', '/vendor/prism-autoloader.min.js', '/content/prism.js'], state.content.emoji && '/content/emoji.js', state.content.mermaid && ['/vendor/mermaid.min.js', '/vendor/panzoom.min.js', '/content/mermaid.js'], + state.content.plotly && ['/vendor/plotly.min.js', '/content/plotly.js'], state.content.mathjax && ['/content/mathjax.js', '/vendor/mathjax/tex-mml-chtml.js'], '/content/index.js', '/content/scroll.js', diff --git a/background/storage.js b/background/storage.js index 8f5e403..8de4d73 100644 --- a/background/storage.js +++ b/background/storage.js @@ -53,6 +53,7 @@ md.storage.defaults = (compilers) => { mermaid: false, syntax: true, toc: false, + plotly: false, }, origins: { 'file://': { diff --git a/build/package.sh b/build/package.sh index 5349c33..4936f21 100755 --- a/build/package.sh +++ b/build/package.sh @@ -31,6 +31,7 @@ sh mdc/build.sh sh mermaid/build.sh sh mithril/build.sh sh panzoom/build.sh +sh plotly/build.sh sh prism/build.sh sh remark/build.sh sh themes/build.sh $browser diff --git a/build/plotly/build.sh b/build/plotly/build.sh new file mode 100755 index 0000000..ab65f05 --- /dev/null +++ b/build/plotly/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# set current working directory to directory of the shell script +cd "$(dirname "$0")" + +# before +npm ci 2> /dev/null || npm i +mkdir -p tmp + +# copy plotly.min.js +cp node_modules/plotly.js-dist-min/plotly.min.js ../../vendor/ + +# after +rm -rf node_modules/ tmp/ \ No newline at end of file diff --git a/build/plotly/package.json b/build/plotly/package.json new file mode 100644 index 0000000..26492dd --- /dev/null +++ b/build/plotly/package.json @@ -0,0 +1,12 @@ +{ + "name": "markdown-viewer", + "version": "0.0.0", + "description": "Markdown Viewer / Browser Extension", + "private": true, + "dependencies": { + "plotly.js-dist-min": "2.30.1" + }, + "engines": { + "node": ">=18.0.0" + } +} \ No newline at end of file diff --git a/content/index.css b/content/index.css index 63b8dd9..a41fb1a 100644 --- a/content/index.css +++ b/content/index.css @@ -1,4 +1,3 @@ - /*---------------------------------------------------------------------------*/ /*global*/ @@ -359,3 +358,10 @@ img.emojione { /* prevent img stretch */ width: auto; } + +.plotly-container { + width: 100%; + min-height: 400px; + resize: vertical; + overflow: hidden; +} diff --git a/content/index.js b/content/index.js index b7cf50e..12e0de9 100644 --- a/content/index.js +++ b/content/index.js @@ -1,4 +1,3 @@ - var $ = document.querySelector.bind(document) var state = { @@ -110,6 +109,10 @@ var update = (update) => { if (state.content.mathjax) { setTimeout(() => mj.render(), 60) } + + if (state.content.plotly) { + setTimeout(() => plt.render(), 80) + } } var render = (md) => { @@ -129,6 +132,12 @@ var render = (md) => { '' ) } + if (state.content.plotly) { + state.html = state.html.replace( + //gi, + '' + ) + } if (state.content.toc) { state.toc = toc.render(state.html) } diff --git a/content/plotly.js b/content/plotly.js new file mode 100644 index 0000000..9fe8442 --- /dev/null +++ b/content/plotly.js @@ -0,0 +1,48 @@ +var plt = (() => { + var loaded = false + + var walk = (regex, string, result = [], match = regex.exec(string)) => + !match ? result : walk(regex, string, result.concat(match[1])) + + function decodeHtml(html) { + var txt = document.createElement('textarea') + txt.innerHTML = html + return txt.value + } + + return { + render: () => { + var definitions = walk(/
([\s\S]+?)<\/code><\/pre>/gi, state.html)
+      console.log('Definitions found:', definitions)
+      
+      Array.from(document.querySelectorAll('pre code.plotly')).forEach((plot, index) => {
+        try {
+          let rawData = definitions[index]
+          console.log('Before decode:', rawData)
+          
+          // Decode HTML entities
+          rawData = decodeHtml(rawData.trim())
+          console.log('After decode:', rawData)
+          console.log('First character code:', rawData.charCodeAt(0))
+          
+          // Remove any BOM or invisible characters
+          rawData = rawData.replace(/^\uFEFF/, '')
+          rawData = rawData.replace(/^\s+|\s+$/g, '')
+          console.log('After cleanup:', rawData)
+          
+          const plotData = JSON.parse(rawData)
+          const plotDiv = document.createElement('div')
+          plotDiv.className = 'plotly-container'
+          plot.parentElement.replaceWith(plotDiv)
+          Plotly.newPlot(plotDiv, plotData.data, plotData.layout || {})
+        }
+        catch (err) {
+          console.error('Failed to render Plotly plot:', err)
+          console.error('Raw data that caused error:', definitions[index])
+        }
+      })
+      
+      loaded = true
+    }
+  }
+})()
\ No newline at end of file
diff --git a/content/scroll.js b/content/scroll.js
index 8e833a5..4acc815 100644
--- a/content/scroll.js
+++ b/content/scroll.js
@@ -1,4 +1,3 @@
-
 var scroll = (() => {
   function onload (done) {
     Promise.all([
@@ -67,6 +66,21 @@ var scroll = (() => {
             }
           }, 50)
         }
+      }),
+      new Promise((resolve) => {
+        var plots = Array.from(document.querySelectorAll('code.plotly'))
+        if (!state.content.plotly || !plots.length) {
+          resolve()
+        }
+        else {
+          var timeout = setInterval(() => {
+            var containers = Array.from(document.querySelectorAll('.plotly-container'))
+            if (plots.length === containers.length) {
+              clearInterval(timeout)
+              resolve()
+            }
+          }, 50)
+        }
       })
     ]).then(done)
   }
diff --git a/manifest.chrome.json b/manifest.chrome.json
index 7f52256..13c3fa0 100644
--- a/manifest.chrome.json
+++ b/manifest.chrome.json
@@ -2,7 +2,7 @@
   "manifest_version": 3,
   "name"            : "Markdown Viewer",
   "version"         : "5.3",
-  "description"     : "Dark Mode • Themes • Autoreload • Mermaid Diagrams • MathJax • ToC • Syntax Highlighting",
+  "description"     : "Dark Mode • Themes • Autoreload • Mermaid Diagrams • MathJax • Plotly Charts • ToC • Syntax Highlighting",
 
   "homepage_url": "https://chromewebstore.google.com/detail/markdown-viewer/ckkdlimhmcjmikdlpkmbgfkaikojcbjk",
 
diff --git a/popup/index.js b/popup/index.js
index fe01bae..232bfa7 100644
--- a/popup/index.js
+++ b/popup/index.js
@@ -65,6 +65,7 @@ var Popup = () => {
         mathjax: 'Render MathJax formulas',
         mermaid: 'Mermaid diagrams',
         syntax: 'Syntax highlighting for fenced code blocks',
+        plotly: 'Plotly charts',
       }
     },
     settings: {}

From 0e26f54ab7026757b6ae5b3007bdef926b9a85db Mon Sep 17 00:00:00 2001
From: Avi Herman 
Date: Wed, 12 Feb 2025 21:23:25 -0500
Subject: [PATCH 2/3] added plotly to firefox

---
 background/index.js   | 45 ++++++++++++++-----------------------------
 manifest.firefox.json |  5 +----
 popup/index.js        | 10 ++++++++--
 3 files changed, 23 insertions(+), 37 deletions(-)

diff --git a/background/index.js b/background/index.js
index 54a1e7b..887401d 100644
--- a/background/index.js
+++ b/background/index.js
@@ -1,39 +1,22 @@
-
-importScripts('/vendor/markdown-it.min.js')
-importScripts('/vendor/marked.min.js')
-importScripts('/vendor/remark.min.js')
-importScripts('/background/compilers/markdown-it.js')
-importScripts('/background/compilers/marked.js')
-importScripts('/background/compilers/remark.js')
-
-importScripts('/background/storage.js')
-importScripts('/background/webrequest.js')
-importScripts('/background/detect.js')
-importScripts('/background/inject.js')
-importScripts('/background/messages.js')
-importScripts('/background/mathjax.js')
-importScripts('/background/xhr.js')
-importScripts('/background/icon.js')
-
-;(() => {
-  var storage = md.storage(md)
-  var inject = md.inject({storage})
-  var detect = md.detect({storage, inject})
-  var webrequest = md.webrequest({storage})
-  var mathjax = md.mathjax()
-  var xhr = md.xhr()
-  var icon = md.icon({storage})
+(() => {
+  var storage = md.storage(md);
+  var inject = md.inject({storage});
+  var detect = md.detect({storage, inject});
+  var webrequest = md.webrequest({storage});
+  var mathjax = md.mathjax();
+  var xhr = md.xhr();
+  var icon = md.icon({storage});
 
   var compilers = Object.keys(md.compilers)
     .reduce((all, compiler) => (
       all[compiler] = md.compilers[compiler]({storage}),
       all
-    ), {})
+    ), {});
 
-  var messages = md.messages({storage, compilers, mathjax, xhr, webrequest, icon})
+  var messages = md.messages({storage, compilers, mathjax, xhr, webrequest, icon});
 
-  chrome.tabs.onUpdated.addListener(detect.tab)
-  chrome.runtime.onMessage.addListener(messages)
+  chrome.tabs.onUpdated.addListener(detect.tab);
+  chrome.runtime.onMessage.addListener(messages);
 
-  icon()
-})()
+  icon();
+})();
diff --git a/manifest.firefox.json b/manifest.firefox.json
index 8a0a721..6715901 100644
--- a/manifest.firefox.json
+++ b/manifest.firefox.json
@@ -26,16 +26,14 @@
     "default_popup": "/popup/index.html"
   },
 
-  "background" : {
+  "background": {
     "scripts": [
       "/vendor/markdown-it.min.js",
       "/vendor/marked.min.js",
       "/vendor/remark.min.js",
-
       "/background/compilers/markdown-it.js",
       "/background/compilers/marked.js",
       "/background/compilers/remark.js",
-
       "/background/storage.js",
       "/background/webrequest.js",
       "/background/detect.js",
@@ -44,7 +42,6 @@
       "/background/mathjax.js",
       "/background/xhr.js",
       "/background/icon.js",
-
       "/background/index.js"
     ]
   },
diff --git a/popup/index.js b/popup/index.js
index 232bfa7..32669aa 100644
--- a/popup/index.js
+++ b/popup/index.js
@@ -1,4 +1,3 @@
-
 var Popup = () => {
 
   var state = {
@@ -146,6 +145,10 @@ var Popup = () => {
   }
 
   var init = (res) => {
+    if (!res) {
+      console.log('Failed to get initial state');
+      return;
+    }
     state.compiler = res.compiler
     state.options = res.options
     state.content = res.content
@@ -172,7 +175,10 @@ var Popup = () => {
     tabs: (vnode) => {
       state._tabs = mdc.tabs.MDCTabBar.attachTo(vnode.dom)
       setTimeout(() => {
-        state._tabs.activeTabIndex = state.tabs.indexOf(state.tab)
+        const tabIndex = state.tabs.indexOf(state.tab)
+        if (tabIndex >= 0) {
+          state._tabs.activeTabIndex = tabIndex
+        }
       }, 250)
     }
   }

From 7189002f1e25ae91289b90ee88e6a61faf8d9889 Mon Sep 17 00:00:00 2001
From: Avi Herman 
Date: Thu, 6 Mar 2025 15:58:48 -0500
Subject: [PATCH 3/3] Chrome fix

---
 background/index.js | 20 ++++++++++++++++++++
 background/md.js    |  5 +++++
 2 files changed, 25 insertions(+)
 create mode 100644 background/md.js

diff --git a/background/index.js b/background/index.js
index 887401d..4633693 100644
--- a/background/index.js
+++ b/background/index.js
@@ -1,3 +1,23 @@
+// Import all required scripts
+importScripts(
+  '/vendor/markdown-it.min.js',
+  '/vendor/marked.min.js',
+  '/vendor/remark.min.js',
+  '/background/md.js',
+  '/background/compilers/markdown-it.js',
+  '/background/compilers/marked.js',
+  '/background/compilers/remark.js',
+  '/background/storage.js',
+  '/background/webrequest.js',
+  '/background/detect.js',
+  '/background/inject.js',
+  '/background/messages.js',
+  '/background/mathjax.js',
+  '/background/xhr.js',
+  '/background/icon.js'
+);
+
+// Then initialize everything
 (() => {
   var storage = md.storage(md);
   var inject = md.inject({storage});
diff --git a/background/md.js b/background/md.js
new file mode 100644
index 0000000..a2987ed
--- /dev/null
+++ b/background/md.js
@@ -0,0 +1,5 @@
+// Create the md namespace
+var md = {};
+
+// Export the namespace
+self.md = md;