Skip to content

Add plotly diagrams as a feature #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 33 additions & 30 deletions background/index.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,42 @@
// 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'
);

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})
// Then initialize everything
(() => {
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();
})();
1 change: 1 addition & 0 deletions background/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
5 changes: 5 additions & 0 deletions background/md.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Create the md namespace
var md = {};

// Export the namespace
self.md = md;
1 change: 1 addition & 0 deletions background/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ md.storage.defaults = (compilers) => {
mermaid: false,
syntax: true,
toc: false,
plotly: false,
},
origins: {
'file://': {
Expand Down
1 change: 1 addition & 0 deletions build/package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions build/plotly/build.sh
Original file line number Diff line number Diff line change
@@ -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/
12 changes: 12 additions & 0 deletions build/plotly/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
8 changes: 7 additions & 1 deletion content/index.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/*---------------------------------------------------------------------------*/
/*global*/

Expand Down Expand Up @@ -359,3 +358,10 @@ img.emojione {
/* prevent img stretch */
width: auto;
}

.plotly-container {
width: 100%;
min-height: 400px;
resize: vertical;
overflow: hidden;
}
11 changes: 10 additions & 1 deletion content/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

var $ = document.querySelector.bind(document)

var state = {
Expand Down Expand Up @@ -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) => {
Expand All @@ -129,6 +132,12 @@ var render = (md) => {
'<code class="mermaid">'
)
}
if (state.content.plotly) {
state.html = state.html.replace(
/<code class="language-(?:plotly)">/gi,
'<code class="plotly">'
)
}
if (state.content.toc) {
state.toc = toc.render(state.html)
}
Expand Down
48 changes: 48 additions & 0 deletions content/plotly.js
Original file line number Diff line number Diff line change
@@ -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(/<pre><code class="plotly">([\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
}
}
})()
16 changes: 15 additions & 1 deletion content/scroll.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

var scroll = (() => {
function onload (done) {
Promise.all([
Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion manifest.chrome.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",

Expand Down
5 changes: 1 addition & 4 deletions manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -44,7 +42,6 @@
"/background/mathjax.js",
"/background/xhr.js",
"/background/icon.js",

"/background/index.js"
]
},
Expand Down
11 changes: 9 additions & 2 deletions popup/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

var Popup = () => {

var state = {
Expand Down Expand Up @@ -65,6 +64,7 @@ var Popup = () => {
mathjax: 'Render MathJax formulas',
mermaid: 'Mermaid diagrams',
syntax: 'Syntax highlighting for fenced code blocks',
plotly: 'Plotly charts',
}
},
settings: {}
Expand Down Expand Up @@ -145,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
Expand All @@ -171,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)
}
}
Expand Down