This repository has been archived by the owner on Oct 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* create quarto docs website * add psefiles * add just file to allow building locally or in CI
- Loading branch information
Showing
15 changed files
with
430 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/.quarto/ | ||
_site/ | ||
doc/ | ||
examples/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
title: Molstar support | ||
author: Jannik Buhr | ||
version: 0.0.1 | ||
contributes: | ||
shortcodes: | ||
- molstar.lua |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
div .molstar-app { | ||
position: relative; | ||
width: 100%; | ||
padding-bottom: 56.25%; | ||
margin-bottom: 1rem; | ||
} | ||
|
||
.msp-plugin .msp-layout-expanded { | ||
z-index: 1; | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,339 @@ | ||
-- for development: | ||
local p = function(x) | ||
quarto.log.output(x) | ||
end | ||
|
||
---@type boolean | ||
local useIframes = false | ||
if quarto.doc.isFormat("revealjs") then | ||
useIframes = true | ||
end | ||
|
||
---@param path string Path to the file | ||
---@return string|nil The file content | ||
local function readFile(path) | ||
local file = io.open(path, "r") | ||
if not file then return nil end | ||
local content = file:read "*a" | ||
file:close() | ||
return content | ||
end | ||
|
||
---Format string like in bash or python, | ||
---e.g. f('Hello ${one}', {one = 'world'}) | ||
---@param s string The string to format | ||
---@param kwargs {[string]: string} A table with key-value replacemen pairs | ||
---@return string | ||
local function f(s, kwargs) | ||
return (s:gsub('($%b{})', function(w) return kwargs[w:sub(3, -2)] or w end)) | ||
end | ||
|
||
---Get the file extension | ||
---@param path string | ||
---@return string | ||
local function fileExt(path) | ||
return path:match("[^.]+$") | ||
end | ||
|
||
---Add molstar css and js dependencies. | ||
---Can be linked / embedded for regular html documents, | ||
---but have to be copied for revealjs to be used in iframes | ||
local function addDependencies() | ||
quarto.doc.addHtmlDependency { | ||
name = 'molstar', | ||
version = 'v3.13.0', | ||
scripts = { './assets/molstar.js' }, | ||
stylesheets = { './assets/molstar.css', 'assets/app-container.css' }, | ||
} | ||
if useIframes then | ||
quarto.doc.addFormatResource('./assets/molstar.css') | ||
quarto.doc.addFormatResource('./assets/molstar.js') | ||
end | ||
end | ||
|
||
---Merge user provided molstar options with defaults | ||
---@param userOptions table | ||
---@return string JSON string to pass to molstar | ||
local function mergeMolstarOptions(userOptions) | ||
local defaultOptions = { | ||
layoutIsExpanded = false, | ||
layoutShowControls = false, | ||
layoutShowRemoteState = false, | ||
layoutShowSequence = false, | ||
layoutShowLog = false, | ||
layoutShowLeftPanel = true, | ||
viewportShowExpand = true, | ||
viewportShowSelectionMode = false, | ||
viewportShowAnimation = true, | ||
pdbProvider = "rcsb", | ||
emdbProvider = "rcsb", | ||
} | ||
if userOptions == nil then | ||
return quarto.json.encode(defaultOptions) | ||
end | ||
|
||
for k, v in pairs(userOptions) do | ||
local value = pandoc.utils.stringify(v) | ||
if value == 'true' then value = true end | ||
if value == 'false' then value = false end | ||
defaultOptions[k] = value | ||
end | ||
|
||
return quarto.json.encode(defaultOptions) | ||
end | ||
|
||
---@param viewerFunctionString string | ||
---@return string | ||
local function wrapInlineIframe(viewerFunctionString) | ||
return [[ | ||
<iframe id="${appId}" class="molstar-app" seamless allow="fullscreen" srcdoc=' | ||
<html> | ||
<head> | ||
<script type="text/javascript" src="./molstar.js"></script> | ||
<link rel="stylesheet" type="text/css" href="./molstar.css"/> | ||
</head> | ||
<body> | ||
<div id="${appId}" class="molstar-app"></div> | ||
<script type="text/javascript"> | ||
molstar.Viewer.create("${appId}", ${options}).then(viewer => { | ||
]] .. viewerFunctionString .. [[ | ||
}); | ||
</script> | ||
</body> | ||
</html> | ||
'> | ||
</iframe> | ||
]] | ||
end | ||
|
||
---@param viewerFunctionString string | ||
---@return string | ||
local function wrapInlineDiv(viewerFunctionString) | ||
return [[ | ||
<div id="${appId}" class="molstar-app"></div> | ||
<script type="text/javascript"> | ||
molstar.Viewer.create("${appId}", ${options}).then(viewer => { | ||
]] .. viewerFunctionString .. [[ | ||
}); | ||
</script> | ||
]] | ||
end | ||
|
||
---@param args table | ||
---@return string | ||
local function createViewer(args) | ||
local subs = { | ||
appId = args.appId, | ||
url = args.url, | ||
urlExtension = args.urlExtension, | ||
pdb = args.pdbId, | ||
trajUrl = args.trajUrl, | ||
trajExtension = args.trajExtension, | ||
volumeUrl = args.volumeUrl, | ||
volumeExtension = args.volumeExtension, | ||
snapshotUrl = args.snapshotUrl, | ||
snapshotExtension = args.snapshotExtension, | ||
afdb = args.afdb, | ||
data = args.data, | ||
options = mergeMolstarOptions(args.userOptions) | ||
} | ||
|
||
local wrapper | ||
local viewerFunction | ||
|
||
if useIframes then | ||
wrapper = wrapInlineIframe | ||
else | ||
wrapper = wrapInlineDiv | ||
end | ||
|
||
if args.data then -- if we have embedded data, use it | ||
viewerFunction = 'viewer.loadStructureFromData(`${data}`, format="${urlExtension}");' | ||
elseif args.pdbId then -- fetch from rcsb pdbb if an ID is given | ||
viewerFunction = 'viewer.loadPdb("${pdb}");' | ||
elseif args.url and args.trajUrl then -- load topology + trajectory if both are given | ||
viewerFunction = [[ | ||
viewer.loadTrajectory( | ||
{ | ||
model: { | ||
kind: "model-url", url: "${url}", format: "${urlExtension}" | ||
}, | ||
coordinates: { | ||
kind: "coordinates-url", url: "${trajUrl}", | ||
format: "${trajExtension}", isBinary: true | ||
} | ||
} | ||
); | ||
]] | ||
elseif args.volumeUrl and args.volumeExtension then | ||
viewerFunction = [[ | ||
viewer.loadStructureFromUrl("${url}", "${urlExtension}") | ||
viewer.loadVolumeFromUrl( | ||
{url: "${volumeUrl}", | ||
format: "${volumeExtension}", | ||
isBinary: false}, | ||
[{type: "absolute", | ||
alpha: 1, | ||
value: 0.001, | ||
} | ||
] | ||
); | ||
]] | ||
elseif args.snapshotUrl and args.snapshotExtension then | ||
viewerFunction = 'viewer.loadSnapshotFromUrl(url="${snapshotUrl}", "${snapshotExtension}");' | ||
elseif args.afdb then | ||
viewerFunction = 'viewer.loadAlphaFoldDb(afdb="${afdb}")' | ||
elseif args.urlExtension == 'mvsj' then | ||
viewerFunction = 'viewer.loadMvsFromUrl(url="${url}", "${urlExtension}");' | ||
else -- otherwise read from url (local or remote) | ||
viewerFunction = 'viewer.loadStructureFromUrl("${url}", format="${urlExtension}");' | ||
end | ||
|
||
return f(wrapper(viewerFunction), subs) | ||
end | ||
|
||
return { | ||
['mol-rcsb'] = function(args, kwargs) | ||
-- return early if the output format is unsupported | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local pdbId = pandoc.utils.stringify(args[1]) | ||
local appId = 'app-' .. pdbId | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
pdbId = pdbId, | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-afdb'] = function(args, kwargs) | ||
-- return early if the output format is unsupported | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local afdb = pandoc.utils.stringify(args[1]) | ||
local appId = 'app-' .. afdb | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
afdb = afdb, | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-url'] = function(args, kwargs, meta) | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local url = pandoc.utils.stringify(args[1]) | ||
local appId = 'app-' .. url | ||
local urlExtension = fileExt(url) | ||
local molstarMeta = '' | ||
if meta.molstar then | ||
molstarMeta = pandoc.utils.stringify(meta.molstar) | ||
end | ||
local pdbContent | ||
if molstarMeta == 'embed' and not useIframes then | ||
---@type string|nil | ||
pdbContent = readFile(url) | ||
end | ||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
url = url, | ||
data = pdbContent, | ||
urlExtension = urlExtension, | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-snapshot'] = function(args, kwargs, meta) | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local url = pandoc.utils.stringify(args[1]) | ||
local appId = 'app-' .. url | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
snapshotUrl = url, | ||
snapshotExtension = fileExt(url), | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-traj'] = function(args, kwargs) | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local url = pandoc.utils.stringify(args[1]) | ||
local trajUrl = pandoc.utils.stringify(args[2]) | ||
local appId = 'app-' .. url .. trajUrl | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
url = url, | ||
trajUrl = trajUrl, | ||
urlExtension = fileExt(url), | ||
trajExtension = fileExt(trajUrl), | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-volume'] = function(args, kwargs) | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local url = pandoc.utils.stringify(args[1]) | ||
local volumeUrl = pandoc.utils.stringify(args[2]) | ||
local appId = 'app-' .. url .. volumeUrl | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
url = url, | ||
volumeUrl = volumeUrl, | ||
urlExtension = fileExt(url), | ||
volumeExtension = fileExt(volumeUrl), | ||
userOptions = kwargs | ||
}) | ||
end, | ||
|
||
['mol-json'] = function(args, kwargs) | ||
if not quarto.doc.isFormat("html:js") then | ||
return pandoc.Null() | ||
end | ||
|
||
addDependencies() | ||
|
||
local url = pandoc.utils.stringify(args[1]) | ||
local appId = 'app-' .. url | ||
|
||
return pandoc.RawBlock('html', createViewer { | ||
appId = appId, | ||
url = url, | ||
urlExtension = fileExt(url), | ||
userOptions = kwargs | ||
} | ||
) | ||
end, | ||
|
||
} |
Oops, something went wrong.