@open-iframe-resizer/vue
Version:
Open-source modern iframe resizer component
256 lines (255 loc) • 8.19 kB
JavaScript
import { defineComponent as O, ref as k, onMounted as M, onBeforeUnmount as B, createElementBlock as P, openBlock as A, mergeProps as H } from "vue";
const S = () => typeof window < "u", _ = () => window.self !== window.top, v = (e) => e instanceof HTMLIFrameElement, D = (e) => {
window.document.readyState === "complete" ? e() : window.addEventListener("load", e);
}, T = (e, t) => {
t(), e.addEventListener("load", t);
}, x = (e, t) => {
var n, r;
const i = ((n = e.contentWindow) == null ? void 0 : n.document.readyState) === "complete";
return e.src !== "about:blank" && ((r = e.contentWindow) == null ? void 0 : r.location.href) !== "about:blank" && i ? t() : e.addEventListener("load", t);
}, C = () => ({ offsetSize: 0, checkOrigin: !0, enableLegacyLibSupport: !1 }), W = (e) => {
try {
return new URL(e.src).origin === window.location.origin;
} catch {
return !1;
}
}, F = (e) => {
try {
const t = new URL(e.src).origin;
if (t !== "about:blank")
return t;
} catch {
}
return null;
}, $ = (e) => (Object.keys(e).forEach((t) => e[t] === void 0 && delete e[t]), e), E = (e) => {
const { height: t, width: n } = e.getBoundingClientRect();
return { height: Math.ceil(t), width: Math.ceil(n) };
}, m = (e, t) => e ? t ? e.querySelector(t) : e.documentElement : null, z = (e, t) => {
e && (t.bodyPadding && (e.body.style.padding = t.bodyPadding), t.bodyMargin && (e.body.style.margin = t.bodyMargin));
}, b = (e) => e <= 100 ? 100 : e <= 120 ? 1e3 : 1e4, N = () => "[iFrameSizer]ID:0:false:false:32:true:true::auto:::0:false:child:auto:true:::true:::false";
function U(e) {
if (typeof e.data != "string" || !e.data.startsWith("[iFrameSizer]") || !e.data.endsWith("mutationObserver") && !e.data.endsWith("resizeObserver"))
return null;
const [t, n] = e.data.split(":"), r = +n;
return r > 0 ? r : null;
}
const w = X();
let f = [];
const j = (e, t) => {
if (!S())
return [];
const n = { ...C(), ...$(e ?? {}) }, r = q(t), i = G(n, r);
return r.map((a) => {
const o = {
iframe: a,
settings: n,
interactionState: { isHovered: !1 },
initContext: { isInitialized: !1, retryAttempts: 0 }
}, s = K(o, i);
return f.push(o), {
unsubscribe: () => {
s(), f = f.filter((d) => d.iframe !== a);
}
};
});
};
function q(e) {
return typeof e == "string" ? Array.from(document.querySelectorAll(e)).filter(v) : e ? v(e) ? [e] : [] : Array.from(document.getElementsByTagName("iframe"));
}
function G(e, t) {
if (Array.isArray(e.checkOrigin))
return e.checkOrigin;
if (!e.checkOrigin)
return [];
const n = [];
for (const r of t) {
const i = F(r);
i && n.push(i);
}
return n;
}
function K(e, t) {
const n = W(e.iframe) ? J(e) : V(e, t), r = Q(e);
return () => {
n(), r();
};
}
function V(e, t) {
const {
iframe: n,
initContext: r,
settings: { checkOrigin: i, enableLegacyLibSupport: a, targetElementSelector: o, bodyPadding: s, bodyMargin: d }
} = e, l = (c) => {
var h;
const I = !i || t.includes(c.origin);
if (!(n.contentWindow !== c.source || !I)) {
if (((h = c.data) == null ? void 0 : h.type) === "iframe-resized") {
const { height: u } = c.data;
u && g({ newHeight: u, registeredElement: e });
return;
}
if (a) {
const u = U(c);
u !== null && g({ newHeight: u, registeredElement: e });
return;
}
}
};
window.addEventListener("message", l);
const L = a ? N() : { type: "iframe-child-init", targetElementSelector: o, bodyPadding: s, bodyMargin: d }, y = () => {
T(n, () => {
var c;
return (c = n.contentWindow) == null ? void 0 : c.postMessage(L, "*");
}), r.retryAttempts++, r.retryTimeoutId = window.setTimeout(y, b(r.retryAttempts));
};
return y(), () => window.removeEventListener("message", l);
}
function J(e) {
const { iframe: t, settings: n } = e, { targetElementSelector: r } = n;
let i = 0;
const a = () => {
const o = m(t.contentDocument, r);
if (!t.contentDocument || !o)
return i++, setTimeout(a, b(i));
z(t.contentDocument, n), w().observe(o);
};
return x(t, a), () => {
const o = m(t.contentDocument, r);
o && w().unobserve(o), t.removeEventListener("load", a);
};
}
function Q({ iframe: e, interactionState: t }) {
const n = () => {
t.isHovered = !0;
}, r = () => {
t.isHovered = !1;
};
return e.addEventListener("mouseenter", n), e.addEventListener("mouseleave", r), () => {
e.removeEventListener("mouseenter", n), e.removeEventListener("mouseleave", r);
};
}
function X() {
let e = null;
return () => {
if (!e) {
const t = ({ target: n }) => {
const r = f.find(({ iframe: d }) => d.contentDocument === n.ownerDocument);
if (!r)
return;
const { iframe: i, settings: a } = r, o = m(i.contentDocument, a.targetElementSelector);
if (!o)
return;
const { height: s } = E(o);
s && g({ newHeight: s, registeredElement: r });
};
e = new ResizeObserver((n) => n.forEach(t));
}
return e;
};
}
function g({ registeredElement: e, newHeight: t }) {
var n;
const { iframe: r, settings: i, interactionState: a, initContext: o } = e;
if (o.isInitialized || (o.isInitialized = !0, clearTimeout(o.retryTimeoutId)), ((n = i.onBeforeIframeResize) == null ? void 0 : n.call(i, { iframe: r, settings: { ...i }, observedHeight: t })) === !1)
return;
const s = r.getBoundingClientRect(), d = t + i.offsetSize;
if (r.style.height = `${d}px`, !i.onIframeResize)
return;
const l = {
iframe: r,
settings: { ...i },
interactionState: { ...a },
previousRenderState: { rect: s },
nextRenderState: { rect: r.getBoundingClientRect() }
};
i.onIframeResize(l);
}
const Y = ee();
let p = !1;
Z();
function Z() {
!S() || !_() || window.addEventListener("message", (e) => {
var t;
((t = e.data) == null ? void 0 : t.type) === "iframe-child-init" && D(() => R(e));
});
}
function R(e, t = 0) {
const { targetElementSelector: n, bodyPadding: r, bodyMargin: i } = e.data, a = m(document, n);
if (p || window.parent !== e.source)
return;
if (!a)
return setTimeout(() => R(e, t + 1), b(t));
z(document, { bodyMargin: i, bodyPadding: r });
const o = Y();
o.disconnect(), o.observe(a), p = !0;
}
function ee() {
let e = null;
return () => (e || (e = new ResizeObserver((t) => {
if (!t[0].target)
return;
const { height: n, width: r } = E(t[0].target), i = {
type: "iframe-resized",
width: r,
height: n
};
window.parent.postMessage(i, "*");
})), e);
}
const te = O({
name: "ResizableIframe",
props: {
offsetSize: [String, Number, Object],
checkOrigin: [Boolean, Array],
onIframeResize: Function,
onBeforeIframeResize: Function,
targetElementSelector: [String],
bodyMargin: [String, Number],
bodyPadding: [String, Number],
enableLegacyLibSupport: Boolean
},
setup(e, { attrs: t }) {
const n = k(null);
let r = [];
const i = (a) => {
const o = {
offsetSize: e.offsetSize,
enableLegacyLibSupport: e.enableLegacyLibSupport,
checkOrigin: e.checkOrigin,
onIframeResize: e.onIframeResize,
onBeforeIframeResize: e.onBeforeIframeResize,
targetElementSelector: e.targetElementSelector,
bodyMargin: e.bodyMargin,
bodyPadding: e.bodyPadding
};
Object.keys(o).forEach((s) => {
o[s] === void 0 && delete o[s];
}), r = j(o, a);
};
return M(() => {
n.value && i(n.value);
}), B(() => {
r.forEach((a) => a.unsubscribe()), r = [];
}), {
iframeRef: n,
attrs: t
};
}
}), ne = (e, t) => {
const n = e.__vccOpts || e;
for (const [r, i] of t)
n[r] = i;
return n;
};
function re(e, t, n, r, i, a) {
return A(), P("iframe", H({ ref: "iframeRef" }, e.$attrs), null, 16);
}
const ie = /* @__PURE__ */ ne(te, [["render", re]]), ae = {
install(e) {
e.component("IframeResizer", ie);
}
};
export {
ie as IframeResizer,
ae as IframeResizerPlugin
};