Changes for page Video Macro

Last modified by Christian Holzner on 2026/09/17 12:11

From version 2.1
edited by Christian Holzner
on 2026/09/17 09:46
Change comment: Video-Makro: allow/referrerpolicy am iframe ergaenzen (Fix fuer gelegentlich schwarzes Video)
To version 5.1
edited by Christian Holzner
on 2026/09/17 11:56
Change comment: Video-Makro: YouTube auf Click-to-Load umgestellt (Fix fuer gelegentlich schwarzes Video, Race Condition bei mehreren Videos/Seite)

Summary

Details

XWiki.JavaScriptExtension[0]
Code
... ... @@ -46,3 +46,25 @@
46 46   });
47 47   });
48 48  });
49 +
50 +;/*ai-video-facade*/(function(){
51 +function onClick(e){
52 +var el=e.target&&e.target.closest?e.target.closest(".ai-video-facade"):null;
53 +if(!el||el.getAttribute("data-loaded")==="1")return;
54 +var src=el.getAttribute("data-embed-src");
55 +if(!src)return;
56 +el.setAttribute("data-loaded","1");
57 +var sep=src.indexOf("?")===-1?"?":"&";
58 +var iframe=document.createElement("iframe");
59 +iframe.src=src+sep+"autoplay=1";
60 +iframe.setAttribute("frameborder","0");
61 +iframe.setAttribute("allow","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share");
62 +iframe.setAttribute("referrerpolicy","strict-origin-when-cross-origin");
63 +iframe.setAttribute("allowfullscreen","");
64 +iframe.style.position="absolute";iframe.style.top="0";iframe.style.left="0";iframe.style.width="100%";iframe.style.height="100%";iframe.style.border="0";
65 +el.innerHTML="";
66 +el.appendChild(iframe);
67 +el.style.cursor="default";
68 +}
69 +document.addEventListener("click",onClick);
70 +})();/* /ai-video-facade */
XWiki.StyleSheetExtension[0]
Code
... ... @@ -9,3 +9,11 @@
9 9   font-weight: normal;
10 10   font-style: normal;
11 11  }
12 +
13 +/* ai-video-facade: Click-to-Load fuer YouTube-Embeds (vermeidet Race Condition beim gleichzeitigen Laden mehrerer iframes) */
14 +.ai-video-facade{position:relative;cursor:pointer;overflow:hidden;background:#000}
15 +.ai-video-facade-thumb{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain;display:block}
16 +.ai-video-facade-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:68px;height:48px;background:rgba(0,0,0,.75);border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s}
17 +.ai-video-facade:hover .ai-video-facade-play{background:#f00}
18 +.ai-video-facade-play::after{content:'';display:block;width:0;height:0;border-style:solid;border-width:11px 0 11px 19px;border-color:transparent transparent transparent #fff;margin-left:4px}
19 +/* /ai-video-facade */
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -1,6 +1,7 @@
1 1  {{velocity}}
2 2  ## Compute the URL of the embedded video from the original web URL.
3 3  #set ($url = '')
4 +#set ($videoId = '')
4 4  #if ($xcontext.macro.params.url.indexOf('dailymotion') != -1)
5 5   ## DailyMotion URLs have the following format:
6 6   ## http://www.dailymotion.com/video/<videoId>_<pretty-name>
... ... @@ -13,6 +13,7 @@
13 13   ## which should be transformed into:
14 14   ## https://youtube.googleapis.com/v/<videoId>
15 15   #set ($url = $xcontext.macro.params.url.replaceAll('^.*?[&?]v=(.*?)(&.*|$)', '//www.youtube.com/embed/$1'))
17 + #set ($videoId = $xcontext.macro.params.url.replaceAll('^.*?[&?]v=(.*?)(&.*|$)', '$1'))
16 16  #elseif ($xcontext.macro.params.url.indexOf('youtu.be') != -1)
17 17   ## YouTube URLs have the following format:
18 18   ## http://www.youtube.com/watch?v=<videoId>&otherParams
... ... @@ -19,6 +19,7 @@
19 19   ## which should be transformed into:
20 20   ## https://youtube.googleapis.com/v/<videoId>
21 21   #set ($url = $xcontext.macro.params.url.replaceAll('^.*youtu.be/(.*?)(&.*|$)', '//www.youtube.com/embed/$1'))
24 + #set ($videoId = $xcontext.macro.params.url.replaceAll('^.*youtu.be/(.*?)(&.*|$)', '$1'))
22 22  #elseif ($xcontext.macro.params.url.indexOf('google') != -1)
23 23   ## Google Video URLs have the following format:
24 24   ## http://video.google.com/videoplay?docid=<videoId>
... ... @@ -47,10 +47,24 @@
47 47  #end
48 48  #set ($width = "width=$width")
49 49  #set ($height = "height=$height")
53 +#set ($styleW = $width.replaceFirst('^width=', ''))
54 +#set ($styleH = $height.replaceFirst('^height=', ''))
50 50  {{/velocity}}
51 51  
52 -{{velocity}}#if ("$!url" != '')
57 +{{velocity}}#if ("$!videoId" != '')
58 + ## Click-to-Load Facade (vermeidet Race Condition beim gleichzeitigen
59 + ## Laden mehrerer YouTube-iframes -- siehe patch_video_macro_facade.ps1)
60 + #set ($discard = $xwiki.jsx.use('Macros.Video20'))
61 + #set ($discard = $xwiki.ssx.use('Macros.Video20'))
62 + #set ($thumbUrl = "https://i.ytimg.com/vi/${videoId}/hqdefault.jpg")
53 53   {{html clean="false"}}
64 + <div$!{embedContainerClass} class="ai-video-facade $!embedItemClass" data-embed-src="$!escapetool.xml($url)" style="width:$!styleW;height:$!styleH">
65 + <img class="ai-video-facade-thumb" src="$!escapetool.xml($thumbUrl)" alt="" loading="lazy"/>
66 + <div class="ai-video-facade-play" aria-hidden="true"></div>
67 + </div>
68 + {{/html}}
69 +#elseif ("$!url" != '')
70 + {{html clean="false"}}
54 54   <div$!{embedContainerClass}>
55 55   #if ($xcontext.macro.params.url.indexOf('google') != -1)
56 56   <object class="$!embedItemClass" $!width $!height type="application/x-shockwave-flash" data="$!url">
... ... @@ -58,7 +58,7 @@
58 58   <param name="allowFullScreen" value="true"></param>
59 59   </object>
60 60   #else
61 - <iframe class="$!embedItemClass" src="$!url" $!width $!height frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
78 + <iframe class="$!embedItemClass" src="$!url" $!width $!height frameborder="0" loading="lazy" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
62 62   #end
63 63   </div>
64 64   {{/html}}