"use strict";
/**
* Wrap the last X words in an HTML tag to prevent them from wrapping (i.e. orphans)
* @param {HTMLElement} el - iframe element
* @param {Object} opts - Options
* @param {number} [opts.defaultAspectRatio=9/16] - Fallback aspect ratio if height and width are undefined
* @param {number|boolean} [opts.forceRatio=false] - Aspect ratio override (ignores iframe’s actual dimensions)
* @param {boolean} [opts.inlineStyles=true] - Apply inline styles (set to “false” if using CSS)
* @param {boolean} [opts.wrap=true] - Whether or not to add a wrapper div to the iframe. Setting to “false” means the video can’t be displayed wider than its original width.
* @param {string} [opts.classes=""] - Class(es) to add to the wrapper or iframe (depends on wrap option)
*/
export default class FluidFrame {
constructor(el, opts) {
var self = this;
this.el = el;
// Check if target element is an iframe
if (this.el.tagName.toLowerCase() !== "iframe") {
console.warn(
`FluidFrame only works on iframes, not <${this.el.tagName.toLowerCase()}> tags`
);
return false;
}
// Use Object.assign() to merge “opts” object with default values in this.options
this.options = Object.assign(
{},
{
defaultAspectRatio: 9 / 16,
forceRatio: false,// set aspect ratio to use regardless of actual dimensions of iframe
inlineStyles: true,// apply inline styles to wrapper or iframe (depends on wrap option)
wrap: true,// adds a div wrapper around the iframe
classes: "" // custom class(es) to add to the wrapper or iframe (depends on wrap option)
},
opts
);
// If inline styles are disabled, “classes” and “forceRatio” must be defined.
if (
!this.options.inlineStyles &&
!this.options.classes &&
!this.options.forceRatio
) {
console.warn(
"FluidFrame: If inline styles are disabled, a fixed aspect ratio must be defined along with custom classes."
);
return false;
}
// Get intrinsic dimensions
this.width = this.el.width ? parseInt(this.el.width) : this.el.offsetWidth;
this.height = this.el.height ? parseInt(this.el.height) : this.el.offsetHeight;
// Determine the aspect ratio
if (parseFloat(this.options.forceRatio)) {
this.aspectRatio = parseFloat(this.options.forceRatio);
} else {
this.aspectRatio =
!this.width && !this.height
? this.options.defaultAspectRatio
: this.height / this.width;
}
// Wrap iframe in div with padding-top equal to aspect ratio as a percentage
if (this.options.wrap) {
this.wrapper = document.createElement("div");
this.el.parentNode.insertBefore(this.wrapper, this.el);
this.wrapper.appendChild(this.el);
}
// Check for custom classes
if (this.options.classes.length) {
// Check if string contains multiple classes
if (this.options.classes.indexOf(" ") > -1) {
// Convert to array and remove empty items (caused by extra whitespace)
this.options.classes = this.options.classes
.split(" ")
.filter(n => n.length);
} else {
// We still need to convert a single class to an array
// in order to use the spread syntax below.
this.options.classes = [this.options.classes];
}
// Add classes
if (this.options.wrap) {
this.wrapper.classList.add(...this.options.classes);
} else {
this.el.classList.add(...this.options.classes);
}
}
// Add inline styles
if (this.options.inlineStyles) {
if (this.options.wrap) {
this.wrapper.setAttribute(
"style",
`padding-top: ${100 * this.aspectRatio}%; position: relative;`
);
// Set iframe to absolutely fill the parent div
this.el.setAttribute(
"style",
"height: 100%; left: 0; position: absolute; top: 0; width: 100%;"
);
} else {
// Inspired by https://github.com/dollarshaveclub/reframe.js#-noframejs
this.el.setAttribute(
"style", `display: block; height: ${100 * this.aspectRatio}vw; margin-left: auto; margin-right: auto; max-height: ${this.height}px; max-width: 100%; width: ${this.width}px;`
);
}
}
}
}