PageSourceSearch

https://warsight.com/wp-content/uploads/cpm-embed/cpm-embed.js?ver=1790316043

js warsight.com collected 2026-09-26 17:49:57 UTC 17,125 bytes, 273 lines download raw bytes

1(function(){
2  if(window.__cpmViewer)return; window.__cpmViewer=true;
3  var v,img,count,title,cap,credit,link,panel,bT,bC,bCr,bL,items=[],cur=0,creditLabel='Foto: ',linkDefault='Zum Artikel',cpmvSlug='',cpmvName='';
4  // v0.41.0: privacy-light view beacon. Fires at most once per slug+kind per
5  // page load. No cookies, no IDs -- the server only keeps aggregate counts.
6  //
7  // v0.115.0: the archive's address is BAKED IN at serve time (https://archiv.cpm-verlag.com).
8  // It used to be derived by stripping this script's own DAM path off its src,
9  // which silently broke when shortcode v2.9.0 started mirroring this file into
10  // each site's own wp-uploads (DAM-outage resilience, correct in itself): from
11  // a local path the pattern never matched, so every beacon posted to the
12  // script's own URL. The version string is a query parameter, so that wrong
13  // URL resolved to the .js file and answered 200 -- a silent success. Result:
14  // ~50k views/month in July, 3 in August, across all sites. The derivation
15  // stays as a fallback for a mirror written before this change.
16  //
17  // This does NOT make a host page depend on the archive: the beacon is
18  // fire-and-forget (sendBeacon, or fetch with keepalive+no-cors), runs after
19  // DOMContentLoaded, and every path is wrapped -- an unreachable archive costs
20  // the page nothing. The site keeps serving its own mirrored copy of this file.
21  var BASE=(function(){try{
22    var b=window.CPM_DAM_BASE||'https://archiv.cpm-verlag.com';
23    if(b&&b.indexOf('__CPM')!==0)return String(b).replace(/[/]+$/,'');
24    var s=(document.currentScript&&document.currentScript.src)||'';
25    var i=s.indexOf('/api/v1/embed/cpm-embed.js');
26    return i>0?s.slice(0,i):'';
27  }catch(_){return '';}})();
28  var beaconSent={};
29  function beacon(slug,kind){
30    if(!slug||!BASE)return;var key=slug+'|'+kind;if(beaconSent[key])return;beaconSent[key]=true;
31    var url=BASE+'/api/v1/collections/'+encodeURIComponent(slug)+'/view?kind='+kind;
32    try{if(navigator.sendBeacon){navigator.sendBeacon(url);}
33      else{fetch(url,{method:'POST',keepalive:true,mode:'no-cors'});}}catch(_){}
34  }
35  function beaconRenders(){
36    try{document.querySelectorAll('[data-cpm-json][data-slug],.cpm-gallery-data[data-slug]').forEach(function(el){
37      beacon(el.getAttribute('data-slug'),'render');});}catch(_){}
38  }
39  // v0.42.2: collection-name heading on each Laufband, top-left. We read the
40  // name from the band's existing aria-label (no snippet re-paste); a future
41  // snippet may set data-cpm-heading for a custom title, which wins.
42  function bandTitles(){
43    try{document.querySelectorAll('.cpm-band').forEach(function(b){
44      if(b.getAttribute('data-cpm-titled'))return;
45      var t=b.getAttribute('data-cpm-heading')||b.getAttribute('aria-label')||'';
46      t=(t||'').trim();if(!t||!b.parentNode)return;
47      b.setAttribute('data-cpm-titled','1');
48      var el=document.createElement('div');el.className='cpm-band-title';el.textContent=t;
49      b.parentNode.insertBefore(el,b);  // sits ABOVE the band, on the page
50    });}catch(_){}
51  }
52  function onReady(){beaconRenders();bandTitles();}
53  if(document.readyState!=='loading')onReady();
54  else document.addEventListener('DOMContentLoaded',onReady);
55  // belt-and-suspenders: re-run after full load + a short delay, for themes
56  // that inject the band late. The existing-title check makes this idempotent.
57  window.addEventListener('load',bandTitles);
58  setTimeout(bandTitles,1500);
59  function labelFor(island){return island&&island.getAttribute('data-lang')==='en'?'Photo: ':'Foto: ';}
60  function linkLabelFor(island){return island&&island.getAttribute('data-lang')==='en'?'To the article':'Zum Artikel';}
61  var MAX='<svg viewBox="0 0 24 24"><path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5"/></svg>';
62  var MIN='<svg viewBox="0 0 24 24"><path d="M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5"/></svg>';
63  var KPLAY='<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
64  // Align the right panel's title with the (vertically-centred) image's top
65  // edge. The image top is dynamic (depends on its aspect), so we sync it in JS
66  // and never go below the default 64px button clearance. Skipped on the mobile
67  // stacked layout and in full mode (panel hidden) -> CSS padding takes over.
68  function syncCaptionTop(){
69    if(!v||!panel||!img||!v.classList.contains('open'))return;
70    if(window.innerWidth<=760||v.classList.contains('full')){panel.style.paddingTop='';return;}
71    var top=Math.round(img.getBoundingClientRect().top-v.getBoundingClientRect().top);
72    if(top>0)panel.style.paddingTop=Math.max(64,top)+'px';
73  }
74  function build(){
75    v=document.createElement('div');v.className='cpmv';
76    v.innerHTML=
77      '<div class="cpmv-stage">'
78      +'<div class="cpmv-count"></div>'
79      +'<button class="cpmv-nav cpmv-prev" aria-label="Zurueck">&#8249;</button>'
80      +'<img alt="">'
81      +'<button class="cpmv-nav cpmv-next" aria-label="Weiter">&#8250;</button>'
82      +'</div>'
83      +'<aside class="cpmv-panel"><h3 class="cpmv-title"></h3>'
84      +'<p class="cpmv-cap"></p>'
85      +'<a class="cpmv-link" target="_blank" rel="noopener"></a>'
86      +'<p class="cpmv-credit"></p></aside>'
87      +'<button class="cpmv-play" aria-label="Diashow">'+KPLAY+'</button>'
88      +'<button class="cpmv-max" aria-label="Vollbild">'+MAX+'</button>'
89      +'<button class="cpmv-x" aria-label="Schliessen">&times;</button>'
90      +'<div class="cpmv-bottom"><span class="bt"></span> <span class="bc"></span> <a class="bl" target="_blank" rel="noopener"></a> <span class="bcr c"></span></div>';
91    document.body.appendChild(v);
92    img=v.querySelector('img');count=v.querySelector('.cpmv-count');
93    title=v.querySelector('.cpmv-title');cap=v.querySelector('.cpmv-cap');credit=v.querySelector('.cpmv-credit');link=v.querySelector('.cpmv-link');panel=v.querySelector('.cpmv-panel');
94    bT=v.querySelector('.cpmv-bottom .bt');bC=v.querySelector('.cpmv-bottom .bc');bCr=v.querySelector('.cpmv-bottom .bcr');bL=v.querySelector('.cpmv-bottom .bl');
95    v.querySelector('.cpmv-prev').addEventListener('click',function(e){e.stopPropagation();show(cur-1);});
96    v.querySelector('.cpmv-next').addEventListener('click',function(e){e.stopPropagation();show(cur+1);});
97    v.querySelector('.cpmv-x').addEventListener('click',close);
98    v.querySelector('.cpmv-max').addEventListener('click',function(e){e.stopPropagation();toggleFull();});
99    v.querySelector('.cpmv-play').addEventListener('click',function(e){e.stopPropagation();var its=items.slice();close();kStart(cpmvSlug,its,cpmvName);});
100    v.querySelector('.cpmv-stage').addEventListener('click',function(e){if(e.target===e.currentTarget)close();});
101    document.addEventListener('keydown',function(e){
102      if(!v.classList.contains('open'))return;
103      if(e.key==='Escape'){ if(v.classList.contains('full')){toggleFull();} else {close();} }
104      else if(e.key==='ArrowLeft')show(cur-1);
105      else if(e.key==='ArrowRight')show(cur+1);
106    });
107    window.addEventListener('resize',syncCaptionTop);
108  }
109  function toggleFull(){
110    var f=v.classList.toggle('full');
111    v.querySelector('.cpmv-max').innerHTML=f?MIN:MAX;
112    syncCaptionTop();
113  }
114  function show(i){
115    var n=items.length;cur=((i%n)+n)%n;var it=items[cur];
116    img.onload=syncCaptionTop;  // re-align the title once the new image lays out
117    img.src=it.full;img.alt=it.cap||it.title||'';
118    syncCaptionTop();
119    count.textContent=(cur+1)+' / '+n;
120    title.textContent=it.title||'';title.style.display=it.title?'':'none';
121    cap.textContent=it.cap||'';cap.style.display=it.cap?'':'none';
122    credit.textContent=it.credit?(creditLabel+it.credit):'';credit.style.display=it.credit?'':'none';
123    if(it.art){link.href=it.art;link.textContent=it.artlabel||linkDefault;link.style.display='';
124      bL.href=it.art;bL.textContent=it.artlabel||linkDefault;bL.style.display='';}
125    else{link.style.display='none';link.removeAttribute('href');bL.style.display='none';bL.removeAttribute('href');}
126    bT.textContent=it.title||'';
127    bC.textContent=it.cap||'';
128    bCr.textContent=it.credit?(creditLabel+it.credit):'';
129  }
130  function open(its,i,full){ if(!v)build(); items=its;
131    if(full){v.classList.add('full');v.querySelector('.cpmv-max').innerHTML=MIN;}
132    else{v.classList.remove('full');v.querySelector('.cpmv-max').innerHTML=MAX;}
133    show(i||0); v.classList.add('open'); }
134  function close(){ if(v){v.classList.remove('open','full');img.src='';} }
135  // v0.44.7: resolve a gallery's data element. Prefer the content-bearing
136  // CONTAINER (.cpm-band/.cpm-gallery/.cpm-inline carries data-cpm-json) -- it
137  // survives page builders (WPBakery/wpautop strip a standalone island div).
138  // Fall back to the legacy separate .cpm-gallery-data element.
139  function cpmIsland(slug,fromEl){
140    var el=(fromEl&&fromEl.closest)?fromEl.closest('[data-cpm-json]'):null;
141    if(!el&&slug)el=document.querySelector('[data-cpm-json][data-slug="'+slug+'"]');
142    if(!el&&slug)el=document.querySelector('.cpm-gallery-data[data-slug="'+slug+'"]');
143    return el;
144  }
145  document.addEventListener('click',function(e){
146    var a=e.target.closest?e.target.closest('[data-cpmg-slug]'):null;
147    if(!a)return;
148    var island=cpmIsland(a.getAttribute('data-cpmg-slug'),a);
149    if(!island)return;
150    var its;try{its=JSON.parse((island.getAttribute('data-cpm-json')||island.textContent));}catch(_){return;}
151    if(!its||!its.length)return;
152    e.preventDefault();e.stopPropagation();
153    creditLabel=labelFor(island);linkDefault=linkLabelFor(island);
154    cpmvSlug=a.getAttribute('data-cpmg-slug')||'';
155    cpmvName=(island.getAttribute('aria-label')||island.getAttribute('data-cpm-heading')||'').trim();
156    beacon(cpmvSlug,'open');
157    open(its,parseInt(a.getAttribute('data-cpmg-index')||'0',10));
158  },true);
159  // Programmatic open (used by the inline viewer's maximize button).
160  window.cpmvOpen=function(slug,idx,full){
161    var island=cpmIsland(slug,null);
162    if(!island)return;var its;try{its=JSON.parse((island.getAttribute('data-cpm-json')||island.textContent));}catch(_){return;}
163    if(its&&its.length){creditLabel=labelFor(island);linkDefault=linkLabelFor(island);
164      cpmvSlug=slug||'';cpmvName=(island.getAttribute('aria-label')||island.getAttribute('data-cpm-heading')||'').trim();
165      beacon(slug,'open');open(its,idx||0,full);}
166  };
167  // Inline gallery viewer (the [cpm_viewer] widget).
168  function setInline(w,i){
169    var imgs=w.querySelectorAll('.cpm-inline-img');var n=imgs.length;if(!n)return;
170    i=((i%n)+n)%n;
171    for(var k=0;k<n;k++)imgs[k].classList.toggle('active',k===i);
172    w.setAttribute('data-cur',i);
173    var c=w.querySelector('.cpm-inline-count');if(c)c.textContent=(i+1)+' / '+n;
174    var island=cpmIsland(w.getAttribute('data-slug'),w);
175    var side=w.querySelector('.cpm-inline-side');
176    if(island&&side){try{var it=JSON.parse((island.getAttribute('data-cpm-json')||island.textContent))[i];side.innerHTML='';
177      if(it.title){var t=document.createElement('span');t.className='t';t.textContent=it.title;side.appendChild(t);}
178      if(it.cap){var d=document.createElement('p');d.className='d';d.textContent=it.cap;side.appendChild(d);}
179      if(it.art){var lk=document.createElement('a');lk.className='lk';lk.href=it.art;lk.target='_blank';lk.rel='noopener';lk.textContent=it.artlabel||linkLabelFor(island);side.appendChild(lk);}
180      if(it.credit){var c=document.createElement('p');c.className='cr';c.textContent=labelFor(island)+it.credit;side.appendChild(c);}
181    }catch(_){}}
182  }
183  document.addEventListener('click',function(e){
184    var b=e.target.closest?e.target.closest('.cpm-inline-prev,.cpm-inline-next,.cpm-inline-max'):null;
185    if(!b)return;var w=b.closest('.cpm-inline');if(!w)return;
186    e.preventDefault();e.stopPropagation();
187    var cur=parseInt(w.getAttribute('data-cur')||'0',10);
188    if(b.classList.contains('cpm-inline-max')){if(window.cpmvOpen)window.cpmvOpen(w.getAttribute('data-slug'),cur,true);return;}
189    setInline(w,b.classList.contains('cpm-inline-prev')?cur-1:cur+1);
190  },true);
191  // ---- Kinomode (v0.47.0): fullscreen auto-slideshow over a gallery --------
192  // A play button rides each gallery container; click => the .cpmk overlay
193  // crossfades through every image with Ken-Burns motion. No captions/sidebar,
194  // just play + stop (X / Esc). All motion on: randomized order, smooth
195  // crossfade, dynamic motion, ~5s/pic, CPM logo + collection name bottom-left.
196  var kv,ka,kb,kTop=true,kItems=[],kOrder=[],kPos=0,kTimer=null,kWake=null,KSEC=5,KDUR=11;
197  var kPre=['1,0,0,1.22,-8,-6','1.22,-8,-6,1,0,0','1.08,-9,0,1.2,9,0',
198            '1.08,9,0,1.2,-9,0','1.08,0,-9,1.2,0,9','1.2,7,7,1,-7,-7'];
199  function khash(s){var h=0,i;s=s||'';for(i=0;i<s.length;i++){h=((h<<5)-h+s.charCodeAt(i))|0;}return Math.abs(h);}
200  function kShuffle(a){a=a.slice();for(var i=a.length-1;i>0;i--){var j=Math.floor(Math.random()*(i+1)),t=a[i];a[i]=a[j];a[j]=t;}return a;}
201  function kKB(layer,src){
202    var p=kPre[khash(src)%6].split(','),st=layer.style;
203    st.setProperty('--s0',p[0]);st.setProperty('--x0',p[1]+'%');st.setProperty('--y0',p[2]+'%');
204    st.setProperty('--s1',p[3]);st.setProperty('--x1',p[4]+'%');st.setProperty('--y1',p[5]+'%');
205    var d=(0.2+(khash(src)%4)*0.07)*KDUR;
206    st.animation='none';void layer.offsetWidth;  // restart the keyframe
207    st.animation='cpmk-kb '+KDUR.toFixed(2)+'s linear -'+d.toFixed(2)+'s forwards';
208  }
209  // Screen wake lock: keep the display awake during the slideshow. Feature-
210  // detected; re-acquired on tab re-focus (the OS releases it when hidden).
211  function kWakeOn(){try{if(!navigator.wakeLock||document.visibilityState!=='visible'||!kv||!kv.classList.contains('open'))return;navigator.wakeLock.request('screen').then(function(s){kWake=s;}).catch(function(){});}catch(_){}}
212  function kWakeOff(){try{if(kWake){kWake.release();kWake=null;}}catch(_){}}
213  function kBuild(){
214    kv=document.createElement('div');kv.className='cpmk';
215    kv.innerHTML='<img class="cpmk-l cpmk-a" alt="">'
216      +'<img class="cpmk-l cpmk-b" alt="">'
217      +'<div class="cpmk-brand"><img class="cpmk-logo" alt="CPM" src="'+BASE+'/api/v1/embed/cpm-logo.png">'
218      +'<div class="cpmk-title"></div></div>'
219      +'<button class="cpmk-x" type="button" aria-label="Schliessen">&times;</button>';
220    document.body.appendChild(kv);
221    ka=kv.querySelector('.cpmk-a');kb=kv.querySelector('.cpmk-b');
222    kv.querySelector('.cpmk-x').addEventListener('click',kStop);
223    document.addEventListener('keydown',function(e){
224      if(kv&&kv.classList.contains('open')&&e.key==='Escape')kStop();
225    });
226    document.addEventListener('visibilitychange',function(){if(document.visibilityState==='visible')kWakeOn();});
227  }
228  function kShow(idx){
229    var n=kOrder.length;if(!n)return;kPos=((idx%n)+n)%n;
230    var it=kItems[kOrder[kPos]],src=it.full||it.thumb||'';
231    var top=kTop?kb:ka,under=kTop?ka:kb;
232    kKB(top,src);
233    var reveal=function(){top.classList.add('show');under.classList.remove('show');};
234    top.onload=reveal;top.onerror=reveal;top.src=src;
235    if(top.complete&&top.naturalWidth){top.onload=null;reveal();}
236    kTop=!kTop;
237    var nx=kItems[kOrder[(kPos+1)%n]];if(nx){var pi=new Image();pi.src=nx.full||nx.thumb||'';}
238  }
239  function kTick(){if(kTimer)clearTimeout(kTimer);kTimer=setTimeout(function(){kShow(kPos+1);kTick();},Math.max(2,KSEC)*1000);}
240  var kNameCache={},kCurSlug='';
241  function kFetchName(slug,cb){
242    // The Betrachter (.cpm-inline) container carries no collection name, so
243    // pull it from the public JSON (cross-origin allowed since v0.47.1). Only
244    // cache a non-empty name, so a transient blank never poisons the cache.
245    if(!slug||!BASE){cb('');return;}
246    if(kNameCache[slug]){cb(kNameCache[slug]);return;}
247    try{fetch(BASE+'/api/v1/collections/'+encodeURIComponent(slug)).then(function(r){return r.ok?r.json():null;}).then(function(d){
248      var nm=(d&&d.name)?d.name:'';if(nm)kNameCache[slug]=nm;cb(nm);
249    }).catch(function(){cb('');});}catch(_){cb('');}
250  }
251  function kStart(slug,its,name){
252    if(!its||its.length<1)return;if(!kv)kBuild();
253    kCurSlug=slug||'';
254    kItems=its;kOrder=kShuffle(its.map(function(_,i){return i;}));kPos=0;kTop=true;
255    var tEl=kv.querySelector('.cpmk-title');
256    function setT(nm){tEl.textContent=nm||'';tEl.style.display=nm?'':'none';}
257    setT(name);
258    // Open FIRST, then resolve the name -- kFetchName may call back
259    // synchronously on a cache hit, and the callback's open-guard would
260    // otherwise skip setting the title (the "sometimes no title" bug). The
261    // slug check guards against a stale async result from another collection.
262    kv.classList.add('open');
263    if(!name)kFetchName(slug,function(nm){if(kv&&kv.classList.contains('open')&&slug===kCurSlug)setT(nm);});
264    try{if(kv.requestFullscreen)kv.requestFullscreen();}catch(_){}
265    kShow(0);kTick();beacon(slug,'open');kWakeOn();
266  }
267  function kStop(){
268    if(kTimer){clearTimeout(kTimer);kTimer=null;}
269    kWakeOff();
270    if(kv){kv.classList.remove('open');if(ka)ka.src='';if(kb)kb.src='';}
271    try{if(document.fullscreenElement)document.exitFullscreen();}catch(_){}
272  }
273})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.