UNPKG

@wordpress/block-editor

Version:
320 lines (318 loc) 11 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/block-editor/src/components/iframe/index.js var iframe_exports = {}; __export(iframe_exports, { default: () => iframe_default }); module.exports = __toCommonJS(iframe_exports); var import_clsx = __toESM(require("clsx")); var import_element = require("@wordpress/element"); var import_i18n = require("@wordpress/i18n"); var import_compose = require("@wordpress/compose"); var import_components = require("@wordpress/components"); var import_data = require("@wordpress/data"); var import_block_selection_clearer = require("../block-selection-clearer"); var import_writing_flow = require("../writing-flow"); var import_get_compatibility_styles = require("./get-compatibility-styles"); var import_use_scale_canvas = require("./use-scale-canvas"); var import_store = require("../../store"); var import_jsx_runtime = require("react/jsx-runtime"); function bubbleEvent(event, Constructor, frame) { const init = {}; for (const key in event) { init[key] = event[key]; } if (event instanceof frame.contentDocument.defaultView.MouseEvent) { const rect = frame.getBoundingClientRect(); init.clientX += rect.left; init.clientY += rect.top; } const newEvent = new Constructor(event.type, init); if (init.defaultPrevented) { newEvent.preventDefault(); } const cancelled = !frame.dispatchEvent(newEvent); if (cancelled) { event.preventDefault(); } } function useBubbleEvents(iframeDocument) { return (0, import_compose.useRefEffect)(() => { const { defaultView } = iframeDocument; if (!defaultView) { return; } const { frameElement } = defaultView; const html = iframeDocument.documentElement; const eventTypes = ["dragover", "mousemove"]; const handlers = {}; for (const name of eventTypes) { handlers[name] = (event) => { const prototype = Object.getPrototypeOf(event); const constructorName = prototype.constructor.name; const Constructor = window[constructorName]; bubbleEvent(event, Constructor, frameElement); }; html.addEventListener(name, handlers[name]); } return () => { for (const name of eventTypes) { html.removeEventListener(name, handlers[name]); } }; }); } function Iframe({ contentRef, children, tabIndex = 0, scale = 1, frameSize = 0, readonly, forwardedRef: ref, title = (0, import_i18n.__)("Editor canvas"), ...props }) { const { resolvedAssets, isPreviewMode } = (0, import_data.useSelect)((select) => { const { getSettings } = select(import_store.store); const settings = getSettings(); return { resolvedAssets: settings.__unstableResolvedAssets, isPreviewMode: settings.isPreviewMode }; }, []); const { styles = "", scripts = "" } = resolvedAssets; const [iframeDocument, setIframeDocument] = (0, import_element.useState)(); const [bodyClasses, setBodyClasses] = (0, import_element.useState)([]); const clearerRef = (0, import_block_selection_clearer.useBlockSelectionClearer)(); const [before, writingFlowRef, after] = (0, import_writing_flow.useWritingFlow)(); const setRef = (0, import_compose.useRefEffect)((node) => { node._load = () => { setIframeDocument(node.contentDocument); }; let iFrameDocument; function preventFileDropDefault(event) { event.preventDefault(); } function interceptLinkClicks(event) { if (event.target.tagName === "A" && event.target.getAttribute("href")?.startsWith("#")) { event.preventDefault(); iFrameDocument.defaultView.location.hash = event.target.getAttribute("href").slice(1); } } const { ownerDocument } = node; setBodyClasses( Array.from(ownerDocument.body.classList).filter( (name) => name.startsWith("admin-color-") || name.startsWith("post-type-") || name === "wp-embed-responsive" ) ); function onLoad() { const { contentDocument } = node; const { documentElement } = contentDocument; iFrameDocument = contentDocument; documentElement.classList.add("block-editor-iframe__html"); clearerRef(documentElement); contentDocument.dir = ownerDocument.dir; for (const compatStyle of (0, import_get_compatibility_styles.getCompatibilityStyles)()) { if (contentDocument.getElementById(compatStyle.id)) { continue; } contentDocument.head.appendChild( compatStyle.cloneNode(true) ); if (!isPreviewMode) { console.warn( `${compatStyle.id} was added to the iframe incorrectly. Please use block.json or enqueue_block_assets to add styles to the iframe.`, compatStyle ); } } iFrameDocument.addEventListener( "dragover", preventFileDropDefault, false ); iFrameDocument.addEventListener( "drop", preventFileDropDefault, false ); iFrameDocument.addEventListener("click", interceptLinkClicks); } node.addEventListener("load", onLoad); return () => { delete node._load; node.removeEventListener("load", onLoad); iFrameDocument?.removeEventListener( "dragover", preventFileDropDefault ); iFrameDocument?.removeEventListener( "drop", preventFileDropDefault ); iFrameDocument?.removeEventListener("click", interceptLinkClicks); }; }, []); const { contentResizeListener, containerResizeListener, isZoomedOut, scaleContainerWidth } = (0, import_use_scale_canvas.useScaleCanvas)({ scale, frameSize: parseInt(frameSize), iframeDocument }); const disabledRef = (0, import_compose.useDisabled)({ isDisabled: !readonly }); const bodyRef = (0, import_compose.useMergeRefs)([ useBubbleEvents(iframeDocument), contentRef, clearerRef, writingFlowRef, disabledRef ]); const html = `<!doctype html> <html> <head> <meta charset="utf-8"> <base href="${window.location.origin}"> <script>window.frameElement._load()</script> <style> html{ height: auto !important; min-height: 100%; } /* Lowest specificity to not override global styles */ :where(body) { margin: 0; /* Default background color in case zoom out mode background colors the html element */ background-color: white; } </style> ${styles} ${scripts} </head> <body> <script>document.currentScript.parentElement.remove()</script> </body> </html>`; const [src, cleanup] = (0, import_element.useMemo)(() => { const _src = URL.createObjectURL( new window.Blob([html], { type: "text/html" }) ); return [_src, () => URL.revokeObjectURL(_src)]; }, [html]); (0, import_element.useEffect)(() => cleanup, [cleanup]); const shouldRenderFocusCaptureElements = tabIndex >= 0 && !isPreviewMode; const iframe = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ shouldRenderFocusCaptureElements && before, /* @__PURE__ */ (0, import_jsx_runtime.jsx)( "iframe", { ...props, style: { ...props.style, height: props.style?.height, border: 0 }, ref: (0, import_compose.useMergeRefs)([ref, setRef]), tabIndex, src, title, onKeyDown: (event) => { if (props.onKeyDown) { props.onKeyDown(event); } if (event.currentTarget.ownerDocument !== event.target.ownerDocument) { const { stopPropagation } = event.nativeEvent; event.nativeEvent.stopPropagation = () => { }; event.stopPropagation(); event.nativeEvent.stopPropagation = stopPropagation; bubbleEvent( event, window.KeyboardEvent, event.currentTarget ); } }, children: iframeDocument && (0, import_element.createPortal)( /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( "body", { ref: bodyRef, className: (0, import_clsx.default)( "block-editor-iframe__body", "editor-styles-wrapper", ...bodyClasses ), children: [ contentResizeListener, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.__experimentalStyleProvider, { document: iframeDocument, children }) ] } ), iframeDocument.documentElement ) } ), shouldRenderFocusCaptureElements && after ] }); return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "block-editor-iframe__container", children: [ containerResizeListener, /* @__PURE__ */ (0, import_jsx_runtime.jsx)( "div", { className: (0, import_clsx.default)( "block-editor-iframe__scale-container", isZoomedOut && "is-zoomed-out" ), style: { "--wp-block-editor-iframe-zoom-out-scale-container-width": isZoomedOut && `${scaleContainerWidth}px` }, children: iframe } ) ] }); } function IframeIfReady(props, ref) { const isInitialised = (0, import_data.useSelect)( (select) => select(import_store.store).getSettings().__internalIsInitialized, [] ); if (!isInitialised) { return null; } return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Iframe, { ...props, forwardedRef: ref }); } var iframe_default = (0, import_element.forwardRef)(IframeIfReady); //# sourceMappingURL=index.js.map