base.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. function getVariable(el, propertyName) {
  2. return String(getComputedStyle(el).getPropertyValue('--' + propertyName)).trim();
  3. };
  4. function processTheElements() {
  5. var thes = document.querySelectorAll('.the');
  6. for (var i = 0; i < thes.length; i++) {
  7. var v = getVariable(thes[i], thes[i].getAttribute('display-var'));
  8. // only mutate if it actually changed
  9. if (thes[i].textContent != v) {
  10. thes[i].textContent = v;
  11. }
  12. }
  13. }
  14. function _vertical(el, tb) {
  15. var doc, docEl, rect, win;
  16. // return zero for disconnected and hidden (display: none) elements, IE <= 11 only
  17. // running getBoundingClientRect() on a disconnected node in IE throws an error
  18. if ( !el.getClientRects().length ) {
  19. return 0;
  20. }
  21. rect = el.getBoundingClientRect();
  22. doc = el.ownerDocument;
  23. docEl = doc.documentElement;
  24. win = doc.defaultView;
  25. return rect[tb] + win.pageYOffset - docEl.clientTop;
  26. }
  27. function offsetTop(el) {
  28. return _vertical(el, "top");
  29. }
  30. function offsetBottom(el) {
  31. return _vertical(el, "bottom");
  32. }
  33. function offsetBaseline(el) {
  34. var mpbaseline = el.querySelector('.mpbaseline');
  35. return offsetBottom(mpbaseline);
  36. }
  37. function heightAboveBaseline(el) {
  38. var baseline = offsetBaseline(el);
  39. var top = offsetTop(el);
  40. return baseline - top;
  41. }
  42. function positionMarginpars() {
  43. var mpars = document.querySelectorAll('.marginpar > div');
  44. var prevBottom = 0;
  45. mpars.forEach(function(mpar) {
  46. var mpref = document.querySelector('.body #marginref-' + mpar.id);
  47. var baselineref = offsetBottom(mpref);
  48. var heightAB = heightAboveBaseline(mpar);
  49. var height = mpar.offsetHeight;
  50. // round to 1 digit
  51. var top = Math.round((baselineref - heightAB - prevBottom) * 10) / 10;
  52. // only mutate if it actually changed
  53. if (mpar.style.marginTop != Math.max(0, top) + "px") {
  54. mpar.style.marginTop = Math.max(0, top) + "px";
  55. }
  56. // if marginTop would have been negative, the element is now further down by that offset => add it to prevBottom
  57. prevBottom = baselineref - heightAB + height - Math.min(0, top);
  58. });
  59. }
  60. // don't call resize event handlers too often
  61. var optimizedResize = (function() {
  62. var callbacks = [],
  63. running = false;
  64. // fired on resize event
  65. function resize() {
  66. if (!running) {
  67. running = true;
  68. if (window.requestAnimationFrame) {
  69. window.requestAnimationFrame(runCallbacks);
  70. } else {
  71. setTimeout(runCallbacks, 66);
  72. }
  73. }
  74. }
  75. // run the actual callbacks
  76. function runCallbacks() {
  77. callbacks.forEach(function(callback) { callback(); });
  78. running = false;
  79. }
  80. // adds callback to loop
  81. function addCallback(callback) {
  82. if (callback) {
  83. callbacks.push(callback);
  84. }
  85. }
  86. return {
  87. // public method to add additional callback
  88. add: function(callback) {
  89. if (!callbacks.length) {
  90. window.addEventListener('resize', resize);
  91. }
  92. addCallback(callback);
  93. }
  94. }
  95. }());
  96. // setup event listeners
  97. function completed() {
  98. document.removeEventListener("DOMContentLoaded", completed);
  99. window.removeEventListener("load", positionMarginpars);
  100. var observer = new MutationObserver(function() {
  101. processTheElements();
  102. positionMarginpars();
  103. });
  104. observer.observe(document, { attributes: true, childList: true, characterData: true, subtree: true });
  105. // add resize event listener
  106. optimizedResize.add(positionMarginpars);
  107. processTheElements();
  108. positionMarginpars();
  109. }
  110. document.addEventListener("DOMContentLoaded", completed);
  111. window.addEventListener("load", completed);