-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Includes new interactive frontend Updates Manubot Rootstock through the commit: manubot/rootstock@fea9eb8 Based on upgrade instructions at https://github.com/manubot/rootstock/blob/fea9eb80af4ca9d5a116f6c28a6b740272e3c0b9/SETUP.md#merging-upstream-rootstock-changes
- Loading branch information
Showing
22 changed files
with
3,415 additions
and
157 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
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 |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
<title>Manubot</title> | ||
<id>http://www.zotero.org/styles/manubot</id> | ||
<link href="http://www.zotero.org/styles/manubot" rel="self"/> | ||
<link href="https://github.com/greenelab/manubot-rootstock" rel="documentation"/> | ||
<link href="https://github.com/manubot/rootstock" rel="documentation"/> | ||
<author> | ||
<name>Daniel Himmelstein</name> | ||
<email>[email protected]</email> | ||
|
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
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,273 @@ | ||
<!-- accordion plugin --> | ||
|
||
<script> | ||
(function() { | ||
// ///////////////////////// | ||
// DESCRIPTION | ||
// ///////////////////////// | ||
|
||
// This Manubot plugin allows sections of content under <h2> headings | ||
// to be collapsible. | ||
|
||
// ///////////////////////// | ||
// OPTIONS | ||
// ///////////////////////// | ||
|
||
// plugin name prefix for url parameters | ||
const pluginName = 'accordion'; | ||
|
||
// default plugin options | ||
const options = { | ||
// whether to always start expanded ('false'), always start | ||
// collapsed ('true'), or start collapsed when screen small ('auto') | ||
startCollapsed: 'auto', | ||
// whether plugin is on or not | ||
enabled: 'true' | ||
}; | ||
|
||
// change options above, or override with url parameter, eg: | ||
// 'manuscript.html?pluginName-enabled=false' | ||
|
||
// ///////////////////////// | ||
// SCRIPT | ||
// ///////////////////////// | ||
|
||
// start script | ||
function start() { | ||
// run through each <h2> heading | ||
const headings = document.querySelectorAll('h2'); | ||
for (const heading of headings) { | ||
addArrow(heading); | ||
|
||
// start expanded/collapsed based on option | ||
if ( | ||
options.startCollapsed === 'true' || | ||
(options.startCollapsed === 'auto' && isSmallScreen()) | ||
) | ||
collapseHeading(heading); | ||
else | ||
expandHeading(heading); | ||
} | ||
|
||
// attach hash change listener to window | ||
window.addEventListener('hashchange', onHashChange); | ||
} | ||
|
||
// when hash (eg manuscript.html#introduction) changes | ||
function onHashChange() { | ||
const target = getHashTarget(); | ||
if (target) | ||
goToElement(target); | ||
} | ||
|
||
// add arrow to heading | ||
function addArrow(heading) { | ||
// add arrow button | ||
const arrow = document.createElement('button'); | ||
arrow.innerHTML = document.querySelector( | ||
'.icon_angle_down' | ||
).innerHTML; | ||
arrow.classList.add('icon_button', 'accordion_arrow'); | ||
heading.insertBefore(arrow, heading.firstChild); | ||
|
||
// attach click listener to heading and button | ||
heading.addEventListener('click', onHeadingClick); | ||
arrow.addEventListener('click', onArrowClick); | ||
} | ||
|
||
// determine if on mobile-like device with small screen | ||
function isSmallScreen() { | ||
return Math.min(window.innerWidth, window.innerHeight) < 480; | ||
} | ||
|
||
// scroll to and focus element | ||
function goToElement(element, offset) { | ||
// expand accordion section if collapsed | ||
expandElement(element); | ||
const y = | ||
getRectInView(element).top - | ||
getRectInView(document.documentElement).top - | ||
(offset || 0); | ||
// trigger any function listening for "onscroll" event | ||
window.dispatchEvent(new Event('scroll')); | ||
window.scrollTo(0, y); | ||
element.focus(); | ||
} | ||
|
||
// get element that is target of hash | ||
function getHashTarget(link) { | ||
const hash = link ? link.hash : window.location.hash; | ||
const id = hash.slice(1); | ||
let target = document.querySelector( | ||
'[id="' + id + '"], [name="' + id + '"]' | ||
); | ||
if (!target) | ||
return; | ||
|
||
// if figure or table, modify target to get expected element | ||
if (hash.indexOf('#fig:') === 0) | ||
target = target.parentNode; | ||
if (hash.indexOf('#tbl:') === 0) | ||
target = target.nextElementSibling; | ||
|
||
return target; | ||
} | ||
|
||
// when <h2> heading is clicked | ||
function onHeadingClick(event) { | ||
// only collapse if <h2> itself is target of click (eg, user did | ||
// not click on anchor within <h2>) | ||
if (event.target === this) | ||
toggleCollapse(this); | ||
} | ||
|
||
// when arrow button is clicked | ||
function onArrowClick() { | ||
toggleCollapse(this.parentNode); | ||
} | ||
|
||
// collapse section if expanded, expand if collapsed | ||
function toggleCollapse(heading) { | ||
if (heading.dataset.collapsed === 'false') | ||
collapseHeading(heading); | ||
else | ||
expandHeading(heading); | ||
} | ||
|
||
// elements to exclude from collapse, such as table of contents panel, | ||
// hypothesis panel, etc | ||
const exclude = '#toc_panel, div.annotator-frame, #lightbox_overlay'; | ||
|
||
// collapse section | ||
function collapseHeading(heading) { | ||
heading.setAttribute('data-collapsed', 'true'); | ||
const children = getChildren(heading); | ||
for (const child of children) | ||
child.setAttribute('data-collapsed', 'true'); | ||
} | ||
|
||
// expand section | ||
function expandHeading(heading) { | ||
heading.setAttribute('data-collapsed', 'false'); | ||
const children = getChildren(heading); | ||
for (const child of children) | ||
child.setAttribute('data-collapsed', 'false'); | ||
} | ||
|
||
// get list of elements between this <h2> and next <h2> or <h1> | ||
// ("children" of the <h2> section) | ||
function getChildren(heading) { | ||
return nextUntil(heading, 'h2, h1', exclude); | ||
} | ||
|
||
// get position/dimensions of element or viewport | ||
function getRectInView(element) { | ||
let rect = {}; | ||
rect.left = 0; | ||
rect.top = 0; | ||
rect.right = document.documentElement.clientWidth; | ||
rect.bottom = document.documentElement.clientHeight; | ||
let style = {}; | ||
|
||
if (element instanceof HTMLElement) { | ||
rect = element.getBoundingClientRect(); | ||
style = window.getComputedStyle(element); | ||
} | ||
|
||
const margin = {}; | ||
margin.left = parseFloat(style.marginLeftWidth) || 0; | ||
margin.top = parseFloat(style.marginTopWidth) || 0; | ||
margin.right = parseFloat(style.marginRightWidth) || 0; | ||
margin.bottom = parseFloat(style.marginBottomWidth) || 0; | ||
|
||
const border = {}; | ||
border.left = parseFloat(style.borderLeftWidth) || 0; | ||
border.top = parseFloat(style.borderTopWidth) || 0; | ||
border.right = parseFloat(style.borderRightWidth) || 0; | ||
border.bottom = parseFloat(style.borderBottomWidth) || 0; | ||
|
||
const newRect = {}; | ||
newRect.left = rect.left + margin.left + border.left; | ||
newRect.top = rect.top + margin.top + border.top; | ||
newRect.right = rect.right + margin.right + border.right; | ||
newRect.bottom = rect.bottom + margin.bottom + border.bottom; | ||
newRect.width = newRect.right - newRect.left; | ||
newRect.height = newRect.bottom - newRect.top; | ||
|
||
return newRect; | ||
} | ||
|
||
// get list of elements after a start element up to element matching | ||
// query | ||
function nextUntil(element, query, exclude) { | ||
const elements = []; | ||
while (element = element.nextElementSibling, element) { | ||
if (element.matches(query)) | ||
break; | ||
if (!element.matches(exclude)) | ||
elements.push(element); | ||
} | ||
return elements; | ||
} | ||
|
||
// get closest element before specified element that matches query | ||
function firstBefore(element, query) { | ||
while ( | ||
element && | ||
element !== document.body && | ||
!element.matches(query) | ||
) | ||
element = element.previousElementSibling || element.parentNode; | ||
|
||
return element; | ||
} | ||
|
||
// check if element is part of collapsed heading | ||
function isCollapsed(element) { | ||
while (element && element !== document.body) { | ||
if (element.dataset.collapsed === 'true') | ||
return true; | ||
element = element.parentNode; | ||
} | ||
return false; | ||
} | ||
|
||
// expand heading containing element if necesary | ||
function expandElement(element) { | ||
if (isCollapsed(element)) { | ||
const heading = firstBefore(element, 'h2'); | ||
if (heading) | ||
heading.click(); | ||
} | ||
} | ||
|
||
// load options from url parameters | ||
function loadOptions() { | ||
const url = window.location.search; | ||
const params = new URLSearchParams(url); | ||
for (const optionName of Object.keys(options)) { | ||
const paramName = pluginName + '-' + optionName; | ||
const param = params.get(paramName); | ||
if (param !== '' && param !== null) | ||
options[optionName] = param; | ||
} | ||
} | ||
loadOptions(); | ||
|
||
// start script when document is finished loading | ||
if (options.enabled === 'true') | ||
window.addEventListener('load', start); | ||
})(); | ||
</script> | ||
|
||
<!-- angle down icon --> | ||
|
||
<template class="icon_angle_down"> | ||
<!-- modified from: https://fontawesome.com/icons/angle-down --> | ||
<svg width="16" height="16" viewBox="0 0 448 512"> | ||
<path | ||
fill="currentColor" | ||
d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z" | ||
></path> | ||
</svg> | ||
</template> |
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 |
---|---|---|
@@ -1,4 +1,3 @@ | ||
<!-- Insert Analytics Script Below --> | ||
<script> | ||
</script> | ||
<!-- End Analytics Script --> | ||
<!-- analytics plugin --> | ||
|
||
<!-- copy and paste code from Google Analytics or similar service here --> |
Oops, something went wrong.