UNPKG

@open-iframe-resizer/vue

Version:

Open-source modern iframe resizer component

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