src/js/base.js
function getVariable(el, propertyName) {
return String(getComputedStyle(el).getPropertyValue('--' + propertyName)).trim();
};
function processTheElements() {
var thes = document.querySelectorAll('.the');
for (var i = 0; i < thes.length; i++) {
var v = getVariable(thes[i], thes[i].getAttribute('display-var'));
// only mutate if it actually changed
if (thes[i].textContent != v) {
thes[i].textContent = v;
}
}
}
function _vertical(el, tb) {
var doc, docEl, rect, win;
// return zero for disconnected and hidden (display: none) elements, IE <= 11 only
// running getBoundingClientRect() on a disconnected node in IE throws an error
if ( !el.getClientRects().length ) {
return 0;
}
rect = el.getBoundingClientRect();
doc = el.ownerDocument;
docEl = doc.documentElement;
win = doc.defaultView;
return rect[tb] + win.pageYOffset - docEl.clientTop;
}
function offsetTop(el) {
return _vertical(el, "top");
}
function offsetBottom(el) {
return _vertical(el, "bottom");
}
function offsetBaseline(el) {
var mpbaseline = el.querySelector('.mpbaseline');
return offsetBottom(mpbaseline);
}
function heightAboveBaseline(el) {
var baseline = offsetBaseline(el);
var top = offsetTop(el);
return baseline - top;
}
function positionMarginpars() {
var mpars = document.querySelectorAll('.marginpar > div');
var prevBottom = 0;
mpars.forEach(function(mpar) {
var mpref = document.querySelector('.body #marginref-' + mpar.id);
var baselineref = offsetBottom(mpref);
var heightAB = heightAboveBaseline(mpar);
var height = mpar.offsetHeight;
// round to 1 digit
var top = Math.round((baselineref - heightAB - prevBottom) * 10) / 10;
// only mutate if it actually changed
if (mpar.style.marginTop != Math.max(0, top) + "px") {
mpar.style.marginTop = Math.max(0, top) + "px";
}
// if marginTop would have been negative, the element is now further down by that offset => add it to prevBottom
prevBottom = baselineref - heightAB + height - Math.min(0, top);
});
}
// don't call resize event handlers too often
var optimizedResize = (function() {
var callbacks = [],
running = false;
// fired on resize event
function resize() {
if (!running) {
running = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(runCallbacks);
} else {
setTimeout(runCallbacks, 66);
}
}
}
// run the actual callbacks
function runCallbacks() {
callbacks.forEach(function(callback) { callback(); });
running = false;
}
// adds callback to loop
function addCallback(callback) {
if (callback) {
callbacks.push(callback);
}
}
return {
// public method to add additional callback
add: function(callback) {
if (!callbacks.length) {
window.addEventListener('resize', resize);
}
addCallback(callback);
}
}
}());
// setup event listeners
function completed() {
document.removeEventListener("DOMContentLoaded", completed);
window.removeEventListener("load", positionMarginpars);
var observer = new MutationObserver(function() {
processTheElements();
positionMarginpars();
});
observer.observe(document, { attributes: true, childList: true, characterData: true, subtree: true });
// add resize event listener
optimizedResize.add(positionMarginpars);
processTheElements();
positionMarginpars();
}
document.addEventListener("DOMContentLoaded", completed);
window.addEventListener("load", completed);