anyone-oslo/pages

View on GitHub
lib/rails/generators/pages_core/frontend/templates/javascript/lib/responsiveEmbeds.ts

Summary

Maintainability
A
0 mins
Test Coverage
const selectors = [
  'iframe[src*="bandcamp.com"]',
  'iframe[src*="player.vimeo.com"]',
  'iframe[src*="youtube.com"]',
  'iframe[src*="youtube-nocookie.com"]',
  'iframe[src*="spotify.com"]',
  'iframe[src*="kickstarter.com"][src*="video.html"]'
];

function readyHandler(fn: () => void) {
  if (
    document.readyState === "complete" ||
    document.readyState === "interactive"
  ) {
    setTimeout(fn, 1);
  } else {
    document.addEventListener("DOMContentLoaded", fn);
  }
}

function wrapEmbed(embed: HTMLElement): HTMLElement {
  const parent = embed.parentNode as HTMLElement;

  // Recycle the existing container if the embed is already responsive.
  if (
    parent &&
    parent.tagName === "DIV" &&
    parent.childNodes.length === 1 &&
    parent.style.position === "relative"
  ) {
    return parent;
  }

  const wrapper = document.createElement("div");
  if (parent.tagName === "P") {
    parent.parentNode.replaceChild(wrapper, parent);
  } else {
    parent.replaceChild(wrapper, embed);
  }
  wrapper.appendChild(embed);
  return wrapper;
}

function applyEmbed(embed: HTMLElement) {
  const parent = embed.parentNode as HTMLElement;

  if (parent && parent.classList.contains("responsive-embed")) {
    return;
  }

  const width = embed.offsetWidth;
  const height = embed.offsetHeight;
  const ratio = height / width;
  const wrapper = wrapEmbed(embed);

  wrapper.classList.add("responsive-embed");
  wrapper.style.position = "relative";
  wrapper.style.width = "100%";
  wrapper.style.paddingTop = "0";
  wrapper.style.paddingBottom = `${ratio * 100}%`;

  embed.style.position = "absolute";
  embed.style.width = "100%";
  embed.style.height = "100%";
  embed.style.top = "0";
  embed.style.left = "0";
}

export default function responsiveEmbeds() {
  readyHandler(() => {
    document.querySelectorAll(selectors.join(",")).forEach(applyEmbed);
  });
}