PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / sticky-video / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/sticky-video/frontend.js

301 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3 var _typoKeys = {
4 family:'font-family', weight:'font-weight', style:'font-style',
5 decoration:'text-decoration', transform:'text-transform',
6 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
7 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
8 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
9 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
10 };
11 function typoCssVarsForEl(el, obj, prefix) {
12 if (!obj || typeof obj !== 'object') return;
13 Object.keys(_typoKeys).forEach(function (k) {
14 var v = obj[k];
15 if (v === undefined || v === '' || v === null) return;
16 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
17 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
18 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
19 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
20 el.style.setProperty(prefix + _typoKeys[k], String(v));
21 });
22 }
23
24 document.querySelectorAll('.bkbg-sv-app').forEach(function (app) {
25 var opts;
26 try { opts = JSON.parse(app.dataset.opts || '{}'); } catch (e) { return; }
27
28 var videoUrl = opts.videoUrl || '';
29 var videoType = opts.videoType || 'youtube';
30 var posterUrl = opts.posterUrl || '';
31 var title = opts.title || '';
32 var subtitle = opts.subtitle || '';
33 var showTitle = opts.showTitle !== false;
34 var autoplay = !!opts.autoplay;
35 var muted = !!opts.muted;
36 var loop = !!opts.loop;
37 var controls = opts.controls !== false;
38 var aspectRatio = opts.aspectRatio || '16:9';
39 var borderRadius = parseInt(opts.borderRadius) || 16;
40 var stickyEnabled = opts.stickyEnabled !== false;
41 var stickyCorner = opts.stickyCorner || 'bottom-right';
42 var stickyWidth = parseInt(opts.stickyWidth) || 320;
43 var stickyOffset = parseInt(opts.stickyOffset) || 24;
44 var stickyRadius = parseInt(opts.stickyRadius) || 12;
45 var stickyOnPlay = !!opts.stickyOnPlay;
46 var showOverlay = opts.showOverlayPlay !== false;
47 var overlayBg = opts.overlayBg || 'rgba(0,0,0,0.35)';
48 var stickyBg = opts.stickyBg || '#1e293b';
49 var sectionBg = opts.sectionBg || '';
50
51 if (sectionBg) app.style.background = sectionBg;
52
53 // ── Aspect ratio ──
54 var parts = aspectRatio.split(':');
55 var ratioW = parseFloat(parts[0]) || 16;
56 var ratioH = parseFloat(parts[1]) || 9;
57 var padBottom = ((ratioH / ratioW) * 100).toFixed(2) + '%';
58
59 // ── Embed URL helpers ──
60 function getEmbedUrl(ap) {
61 var ytMatch = videoUrl.match(/(?:v=|youtu\.be\/)([A-Za-z0-9_-]{11})/);
62 var vmMatch = videoUrl.match(/vimeo\.com\/(\d+)/);
63 var autoParam = ap ? '1' : '0';
64 if (videoType === 'youtube' && ytMatch) {
65 return 'https://www.youtube.com/embed/' + ytMatch[1]
66 + '?rel=0&autoplay=' + autoParam
67 + (muted ? '&mute=1' : '')
68 + (loop ? '&loop=1&playlist=' + ytMatch[1] : '')
69 + (!controls ? '&controls=0' : '');
70 }
71 if (videoType === 'vimeo' && vmMatch) {
72 return 'https://player.vimeo.com/video/' + vmMatch[1]
73 + '?autoplay=' + autoParam
74 + (muted ? '&muted=1' : '')
75 + (loop ? '&loop=1' : '');
76 }
77 return videoUrl;
78 }
79
80 function el(tag, className) {
81 var d = document.createElement(tag);
82 if (className) d.className = className;
83 return d;
84 }
85
86 // ── Build inline player ──
87 var wrap = el('div', 'bkbg-sv-wrap');
88 typoCssVarsForEl(wrap, opts.titleTypo, '--bksv-tt-');
89 typoCssVarsForEl(wrap, opts.subtitleTypo, '--bksv-st-');
90 wrap.style.setProperty('--bksv-title-fw', opts.titleFontWeight || '700');
91 wrap.style.setProperty('--bksv-title-lh', String(opts.titleLineHeight || 1.2));
92 wrap.style.setProperty('--bksv-st-fw', opts.subtitleFontWeight || '400');
93 wrap.style.setProperty('--bksv-st-lh', String(opts.subtitleLineHeight || 1.5));
94 app.appendChild(wrap);
95
96 var ratioDiv = el('div', 'bkbg-sv-ratio');
97 ratioDiv.style.paddingBottom = padBottom;
98 ratioDiv.style.borderRadius = borderRadius + 'px';
99 wrap.appendChild(ratioDiv);
100
101 var iframeEl = null;
102 var videoEl = null;
103 var isPlaying = false;
104
105 // Poster
106 var posterImg = null;
107 if (posterUrl) {
108 posterImg = el('img', 'bkbg-sv-poster');
109 posterImg.src = posterUrl;
110 posterImg.alt = title;
111 ratioDiv.appendChild(posterImg);
112 }
113
114 // Overlay
115 var overlay = null;
116 if (showOverlay && !autoplay) {
117 overlay = el('div', 'bkbg-sv-overlay');
118 overlay.style.background = overlayBg;
119 var playBtn = el('div', 'bkbg-sv-play-btn');
120 playBtn.textContent = '';
121 overlay.appendChild(playBtn);
122 ratioDiv.appendChild(overlay);
123 }
124
125 // Title overlay
126 if (showTitle && title) {
127 var titleOverlay = el('div', 'bkbg-sv-title-overlay');
128 var titleEl = el('p', 'bkbg-sv-title-text');
129 titleEl.textContent = title;
130 titleOverlay.appendChild(titleEl);
131 if (subtitle) {
132 var subEl = el('p', 'bkbg-sv-subtitle-text');
133 subEl.textContent = subtitle;
134 titleOverlay.appendChild(subEl);
135 }
136 ratioDiv.appendChild(titleOverlay);
137 }
138
139 // ── Load & play ──
140 function startPlay(ap) {
141 isPlaying = true;
142 if (posterImg) posterImg.classList.add('bkbg-sv-hidden');
143 if (overlay) overlay.classList.add('bkbg-sv-hidden');
144
145 if (videoType === 'self') {
146 if (!videoEl) {
147 videoEl = document.createElement('video');
148 videoEl.className = 'bkbg-sv-video';
149 videoEl.src = videoUrl;
150 videoEl.controls = controls;
151 videoEl.muted = muted;
152 videoEl.loop = loop;
153 ratioDiv.appendChild(videoEl);
154 }
155 if (ap) videoEl.play().catch(function(){});
156 } else {
157 if (!iframeEl) {
158 iframeEl = document.createElement('iframe');
159 iframeEl.className = 'bkbg-sv-iframe';
160 iframeEl.allowFullscreen = true;
161 iframeEl.allow = 'autoplay; fullscreen; picture-in-picture';
162 ratioDiv.appendChild(iframeEl);
163 }
164 iframeEl.src = getEmbedUrl(ap);
165 }
166 }
167
168 if (autoplay) {
169 startPlay(true);
170 } else if (overlay) {
171 overlay.addEventListener('click', function () {
172 startPlay(true);
173 if (!stickyOnPlay) isPlayerVisible = false; // will be set properly
174 });
175 }
176 if (posterImg && !overlay) {
177 posterImg.addEventListener('click', function () { startPlay(true); });
178 }
179
180 // ── Sticky / PiP ──
181 if (!stickyEnabled) return;
182
183 var cornerMap = {
184 'bottom-right': 'bkbg-sv-corner-br',
185 'bottom-left': 'bkbg-sv-corner-bl',
186 'top-right': 'bkbg-sv-corner-tr',
187 'top-left': 'bkbg-sv-corner-tl'
188 };
189
190 var stickyEl = el('div', 'bkbg-sv-sticky ' + (cornerMap[stickyCorner] || 'bkbg-sv-corner-br'));
191 stickyEl.style.width = stickyWidth + 'px';
192 stickyEl.style.borderRadius = stickyRadius + 'px';
193 stickyEl.style.background = stickyBg;
194 // Apply offset to correct edges
195 var offsets = stickyCorner.split('-');
196 stickyEl.style[offsets[0]] = stickyOffset + 'px';
197 stickyEl.style[offsets[1]] = stickyOffset + 'px';
198 // Clear the class-set offsets (override)
199 stickyEl.className = 'bkbg-sv-sticky';
200
201 // Sticky inner video ratio
202 var stickyInner = el('div', 'bkbg-sv-sticky-inner');
203 stickyInner.style.borderRadius = stickyRadius + 'px ' + stickyRadius + 'px 0 0';
204 stickyEl.appendChild(stickyInner);
205
206 var stickyRatio = el('div', 'bkbg-sv-ratio');
207 stickyRatio.style.paddingBottom = padBottom;
208 stickyInner.appendChild(stickyRatio);
209
210 // Sticky bar
211 var stickyBar = el('div', 'bkbg-sv-sticky-bar');
212 stickyBar.style.background = stickyBg;
213 stickyBar.style.borderRadius = '0 0 ' + stickyRadius + 'px ' + stickyRadius + 'px';
214
215 var stickyTitle = el('span', 'bkbg-sv-sticky-title');
216 stickyTitle.textContent = title;
217 stickyBar.appendChild(stickyTitle);
218
219 var btnRestore = el('button', 'bkbg-sv-sticky-btn');
220 btnRestore.textContent = '';
221 btnRestore.title = 'Restore';
222 stickyBar.appendChild(btnRestore);
223
224 var btnClose = el('button', 'bkbg-sv-sticky-btn');
225 btnClose.textContent = '';
226 btnClose.title = 'Close';
227 stickyBar.appendChild(btnClose);
228
229 stickyEl.appendChild(stickyBar);
230 document.body.appendChild(stickyEl);
231
232 var stickyIframe = null;
233 var stickyVideo = null;
234 var isStickyVisible = false;
235 var isClosed = false;
236
237 function showSticky() {
238 if (isClosed) return;
239 if (isStickyVisible) return;
240 isStickyVisible = true;
241 stickyEl.classList.add('bkbg-sv-sticky-visible');
242
243 // Build sticky content
244 if (videoType === 'self') {
245 if (!stickyVideo) {
246 stickyVideo = document.createElement('video');
247 stickyVideo.className = 'bkbg-sv-video';
248 stickyVideo.src = videoUrl;
249 stickyVideo.muted = true;
250 stickyVideo.controls = false;
251 stickyVideo.style.borderRadius = stickyRadius + 'px ' + stickyRadius + 'px 0 0';
252 stickyRatio.appendChild(stickyVideo);
253 }
254 } else {
255 if (!stickyIframe) {
256 stickyIframe = document.createElement('iframe');
257 stickyIframe.className = 'bkbg-sv-iframe';
258 stickyIframe.src = getEmbedUrl(true);
259 stickyIframe.allowFullscreen = true;
260 stickyIframe.allow = 'autoplay; fullscreen; picture-in-picture';
261 stickyIframe.style.borderRadius = stickyRadius + 'px ' + stickyRadius + 'px 0 0';
262 stickyRatio.appendChild(stickyIframe);
263 // Mute main iframe to avoid double audio
264 if (iframeEl) iframeEl.src = iframeEl.src.replace('autoplay=1', 'autoplay=0');
265 }
266 }
267 }
268
269 function hideSticky() {
270 if (!isStickyVisible) return;
271 isStickyVisible = false;
272 stickyEl.classList.remove('bkbg-sv-sticky-visible');
273 }
274
275 // Restore: scroll back to original player
276 btnRestore.addEventListener('click', function () {
277 ratioDiv.scrollIntoView({ behavior: 'smooth', block: 'center' });
278 hideSticky();
279 });
280
281 // Close: dismiss sticky permanently
282 btnClose.addEventListener('click', function () {
283 isClosed = true;
284 hideSticky();
285 });
286
287 // IntersectionObserver to detect when inline player leaves view
288 var observer = new IntersectionObserver(function (entries) {
289 var entry = entries[0];
290 if (entry.isIntersecting) {
291 hideSticky();
292 } else {
293 if (stickyOnPlay && !isPlaying) return;
294 showSticky();
295 }
296 }, { threshold: 0.15 });
297
298 observer.observe(ratioDiv);
299 });
300 })();
301