UNPKG

@open-iframe-resizer/vue

Version:

Open-source modern iframe resizer component

256 lines (255 loc) 8.19 kB
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 };