| 1 |
const { registerBlockType } = wp.blocks; |
| 2 |
const { __ } = wp.i18n; |
| 3 |
const { TextControl, PanelBody, SelectControl } = wp.components; |
| 4 |
const { InspectorControls, useBlockProps } = wp.blockEditor || wp.editor; |
| 5 |
|
| 6 |
function toEmbedUrl(input) { |
| 7 |
if (!input) return ""; |
| 8 |
try { |
| 9 |
const url = new URL(input); |
| 10 |
if (url.hostname.includes("youtu.be")) { |
| 11 |
return `https://www.youtube.com/embed/${url.pathname.replace("/", "")}`; |
| 12 |
} |
| 13 |
if (url.hostname.includes("youtube.com")) { |
| 14 |
const v = url.searchParams.get("v"); |
| 15 |
if (v) return `https://www.youtube.com/embed/${v}`; |
| 16 |
// already embed |
| 17 |
if (url.pathname.startsWith("/embed/")) return url.toString(); |
| 18 |
} |
| 19 |
} catch (e) {} |
| 20 |
return input; |
| 21 |
} |
| 22 |
|
| 23 |
function computeStyle({ width, align, padding, margin }) { |
| 24 |
const style = {}; |
| 25 |
if (width) { |
| 26 |
// Accept values like 100%, 800px, 60ch, etc. |
| 27 |
style.maxWidth = width; |
| 28 |
style.width = "100%"; |
| 29 |
} |
| 30 |
if (padding) style.padding = padding; |
| 31 |
if (margin) style.margin = margin; |
| 32 |
if (align === "center") { |
| 33 |
style.marginLeft = "auto"; |
| 34 |
style.marginRight = "auto"; |
| 35 |
} else if (align === "right") { |
| 36 |
style.marginLeft = "auto"; |
| 37 |
} // left = default |
| 38 |
return style; |
| 39 |
} |
| 40 |
|
| 41 |
registerBlockType("ai-builder/aibui-yt-video", { |
| 42 |
title: __("YouTube Video (AI Builder)", "ai-builder"), |
| 43 |
icon: "video-alt3", |
| 44 |
category: "widgets", |
| 45 |
supports: { align: ["wide", "full"], html: false }, |
| 46 |
attributes: { |
| 47 |
url: { type: "string", default: "" }, |
| 48 |
title: { type: "string", default: "" }, |
| 49 |
width: { type: "string", default: "100%" }, |
| 50 |
align: { type: "string", default: "center" }, // left | center | right |
| 51 |
padding: { type: "string", default: "" }, |
| 52 |
margin: { type: "string", default: "" }, |
| 53 |
}, |
| 54 |
edit: (props) => { |
| 55 |
const { attributes, setAttributes } = props; |
| 56 |
const { url, title, width, align, padding, margin } = attributes; |
| 57 |
const blockProps = useBlockProps({ className: "aibui-yt" }); |
| 58 |
const embed = toEmbedUrl(url); |
| 59 |
const wrapStyle = computeStyle({ width, align, padding, margin }); |
| 60 |
return ( |
| 61 |
<div {...blockProps}> |
| 62 |
<InspectorControls> |
| 63 |
<PanelBody title={__("Settings", "ai-builder")} initialOpen> |
| 64 |
<TextControl |
| 65 |
label={__("YouTube URL", "ai-builder")} |
| 66 |
value={url} |
| 67 |
onChange={(v) => setAttributes({ url: v })} |
| 68 |
placeholder="https://www.youtube.com/watch?v=..." |
| 69 |
/> |
| 70 |
<TextControl |
| 71 |
label={__("Title (optional)", "ai-builder")} |
| 72 |
value={title} |
| 73 |
onChange={(v) => setAttributes({ title: v })} |
| 74 |
/> |
| 75 |
<TextControl |
| 76 |
label={__("Max width", "ai-builder")} |
| 77 |
value={width} |
| 78 |
onChange={(v) => setAttributes({ width: v })} |
| 79 |
help={__("Any CSS size (e.g. 100%, 800px, 60ch)", "ai-builder")} |
| 80 |
/> |
| 81 |
<SelectControl |
| 82 |
label={__("Align", "ai-builder")} |
| 83 |
value={align} |
| 84 |
options={[ |
| 85 |
{ label: __("Left", "ai-builder"), value: "left" }, |
| 86 |
{ label: __("Center", "ai-builder"), value: "center" }, |
| 87 |
{ label: __("Right", "ai-builder"), value: "right" }, |
| 88 |
]} |
| 89 |
onChange={(v) => setAttributes({ align: v })} |
| 90 |
/> |
| 91 |
<TextControl |
| 92 |
label={__("Padding (optional)", "ai-builder")} |
| 93 |
value={padding} |
| 94 |
onChange={(v) => setAttributes({ padding: v })} |
| 95 |
placeholder="e.g. 12px 16px" |
| 96 |
/> |
| 97 |
<TextControl |
| 98 |
label={__("Margin (optional)", "ai-builder")} |
| 99 |
value={margin} |
| 100 |
onChange={(v) => setAttributes({ margin: v })} |
| 101 |
placeholder="e.g. 20px auto" |
| 102 |
/> |
| 103 |
</PanelBody> |
| 104 |
</InspectorControls> |
| 105 |
{title ? <h3 className="aibui-yt-title">{title}</h3> : null} |
| 106 |
{embed ? ( |
| 107 |
<div className="aibui-yt-wrap" style={wrapStyle}> |
| 108 |
<iframe |
| 109 |
src={embed} |
| 110 |
title={title || "YouTube video"} |
| 111 |
frameBorder="0" |
| 112 |
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" |
| 113 |
allowFullScreen |
| 114 |
></iframe> |
| 115 |
</div> |
| 116 |
) : ( |
| 117 |
<div className="aibui-yt-placeholder"> |
| 118 |
{__("Paste a YouTube URL in settings", "ai-builder")} |
| 119 |
</div> |
| 120 |
)} |
| 121 |
</div> |
| 122 |
); |
| 123 |
}, |
| 124 |
save: (props) => { |
| 125 |
const { attributes } = props; |
| 126 |
const { url, title, width, align, padding, margin } = attributes; |
| 127 |
const embed = toEmbedUrl(url); |
| 128 |
const blockProps = wp.blockEditor |
| 129 |
? wp.blockEditor.useBlockProps.save({ className: "aibui-yt" }) |
| 130 |
: {}; |
| 131 |
const wrapStyle = computeStyle({ width, align, padding, margin }); |
| 132 |
return ( |
| 133 |
<div {...blockProps}> |
| 134 |
{title ? <h3 className="aibui-yt-title">{title}</h3> : null} |
| 135 |
{embed ? ( |
| 136 |
<div className="aibui-yt-wrap" style={wrapStyle}> |
| 137 |
<iframe |
| 138 |
src={embed} |
| 139 |
title={title || "YouTube video"} |
| 140 |
frameBorder="0" |
| 141 |
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" |
| 142 |
allowFullScreen |
| 143 |
></iframe> |
| 144 |
</div> |
| 145 |
) : null} |
| 146 |
</div> |
| 147 |
); |
| 148 |
}, |
| 149 |
}); |
| 150 |
|