Wiki-Quellcode von Home

Zuletzt geändert von Steffen Rehfuß am 14.08.2026 18:42

Zeige letzte Bearbeiter
1 {{velocity}}
2 ## =====================================================================
3 ## Intranet-Startseite — Hero (TOP-Blogpost) + 12 App-Buttons + 4 Kacheln
4 ## Einfach in den Seiten-Editor (Quelltext/Wiki) einfuegen.
5 ## =====================================================================
6 ##
7 ## ---- KONFIG 1: Blog-Space + Hero-Kategorie + Laufschrift-Kategorie ----
8 #set ($blogSpace = 'Blog') ## technischer Space-Name des Blogs
9 #set ($heroCategory = 'TOP') ## Kategorie, die gross dargestellt wird
10 #set ($breakingCategory = 'Breaking News') ## Kategorie fuer die Laufschrift oben
11 ##
12 ## ---- KONFIG 2: Die 12 App-Buttons (Text / Icon / Link / Farbe) ----
13 ## icon = Font-Awesome-Name (ohne "fa-"). Farbe = beliebiger Hex-Wert.
14 #set ($apps = [
15 {'label':'Abteilung I', 'icon':'search', 'ref':'abteilung01:Main.WebHome', 'color':'#16a085'},
16 {'label':'MyPage', 'icon':'key', 'ref':'MyPage.WebHome', 'color':'#2980b9'},
17 {'label':'Blog', 'icon':'star', 'ref':'Blog.WebHome', 'color':'#8e44ad'},
18 {'label':'Chatbot', 'icon':'pencil-square-o', 'url':"javascript:document.getElementById('toggle-chat-button').click();void(0);", 'color':'#16a085'},
19 {'label':'Forum', 'icon':'group', 'ref':'Forums.WebHome', 'color':'#2980b9'},
20 {'label':'Umfragen', 'icon':'question', 'ref':'XPoll.WebHome', 'color':'#8e44ad'},
21 {'label':'Gruppenräume', 'icon':'life-ring', 'ref':'Rooms.WebHome', 'color':'#16a085'},
22 {'label':'Meine Favoriten', 'icon':'star', 'ref':'Internes.Favoriten.WebHome', 'color':'#2980b9'},
23 {'label':'Kalender', 'icon':'clock-o', 'ref':'MoccaCalendar.WebHome', 'color':'#8e44ad'},
24 {'label':'Org-Chart', 'icon':'sitemap', 'ref':'Internes.Organigramm.WebHome', 'color':'#2c3e50'},
25 {'label':'Tag Filter', 'icon':'filter', 'ref':'KBC Anwendungen.Tag Filter.WebHome', 'color':'#2c3e50'},
26 {'label':'Kantine', 'icon':'coffee', 'ref':'Internes.Kantine.Speiseplan vom 13\.07\.2026 - 17\.07\.2026.WebHome', 'color':'#2c3e50'}
27 ])
28 ##
29 ## ---- Posts laden (neueste zuerst) ----
30 #set ($xwql = "from doc.object(Blog.BlogPostClass) as post where post.published = 1 and doc.hidden = false")
31 #if ($blogSpace != '')
32 #set ($xwql = "$xwql and doc.space like :space")
33 #end
34 #set ($xwql = "$xwql order by post.publishDate desc")
35 #set ($q = $services.query.xwql($xwql).setLimit(30))
36 #if ($blogSpace != '')
37 #set ($q = $q.bindValue('space', "$blogSpace%"))
38 #end
39 #set ($postNames = $q.execute())
40 ##
41 ## ---- Hero (erster TOP-Post) + bis zu 4 Kachel-Posts + neuester Breaking-News-Post bestimmen ----
42 #set ($heroDoc = $NULL)
43 #set ($heroObj = $NULL)
44 #set ($tilePosts = [])
45 #set ($breakingDoc = $NULL)
46 #set ($breakingObj = $NULL)
47 #foreach ($pn in $postNames)
48 #set ($pd = $xwiki.getDocument($pn))
49 #set ($po = $pd.getObject('Blog.BlogPostClass'))
50 #set ($isTop = false)
51 #set ($isBreaking = false)
52 #set ($cats = $po.getValue('category'))
53 #if ($cats)
54 #foreach ($c in $cats)
55 #set ($cn = "$c")
56 #set ($cn = $cn.substring($mathtool.add($cn.lastIndexOf('.'), 1)))
57 #if ($cn == $heroCategory)
58 #set ($isTop = true)
59 #end
60 #if ($cn == $breakingCategory)
61 #set ($isBreaking = true)
62 #end
63 #end
64 #end
65 #if ($isBreaking && !$breakingDoc)
66 #set ($breakingDoc = $pd)
67 #set ($breakingObj = $po)
68 #end
69 #if ($isTop && !$heroDoc)
70 #set ($heroDoc = $pd)
71 #set ($heroObj = $po)
72 #elseif ($tilePosts.size() < 4)
73 #set ($discard = $tilePosts.add($pn))
74 #end
75 #end
76 ## Fallback: kein TOP-Post -> neuesten Post als Hero nehmen
77 #if (!$heroDoc && $postNames.size() > 0)
78 #set ($heroDoc = $xwiki.getDocument($postNames.get(0)))
79 #set ($heroObj = $heroDoc.getObject('Blog.BlogPostClass'))
80 #set ($tilePosts = [])
81 #foreach ($pn in $postNames)
82 #if ("$pn" != "$postNames.get(0)" && $tilePosts.size() < 4)
83 #set ($discard = $tilePosts.add($pn))
84 #end
85 #end
86 #end
87 ##
88 ## ---- Hero-Daten aufbereiten ----
89 #set ($heroImg = '')
90 #if ($heroDoc)
91 #foreach ($att in $heroDoc.getAttachmentList())
92 #if ($heroImg == '' && $att.getMimeType().startsWith('image/'))
93 #set ($heroImg = $heroDoc.getAttachmentURL($att.getFilename()))
94 #end
95 #end
96 #set ($heroTitle = $heroDoc.getPlainTitle())
97 #set ($heroText = "$!heroObj.getValue('extract')")
98 #set ($heroDate = $heroObj.getValue('publishDate'))
99 #end
100 ##
101 ## ---- Laufschrift-Daten aufbereiten ----
102 #if ($breakingDoc)
103 #set ($breakingTitle = $breakingDoc.getPlainTitle())
104 #set ($breakingText = "$!breakingObj.getValue('extract')")
105 #set ($breakingURL = $breakingDoc.getURL('view'))
106 #set ($breakingDate = $breakingObj.getValue('publishDate'))
107 #end
108 ##
109 {{html clean="false" wiki="false"}}
110 <style>
111 ## Seitenkopf (Titel + "Zuletzt geaendert" + Aktionsmenue) auf DIESER Seite ausblenden
112 .document-header { display: none !important; }
113 ## Breadcrumb (Pfad-Navigation) inkl. Wrapper ausblenden
114 #hierarchy_breadcrumb, #hierarchy, .breadcrumb { display: none !important; }
115 ## Horizontale Trennlinie + Rechte-Warnung entfernen, Inhalt nach oben ziehen
116 #mainContentArea > hr { display: none !important; }
117 #missing-required-rights-warning { display: none !important; }
118 ## vom Editor erzeugten Leerabsatz um den Style-Block wegnehmen
119 #xwikicontent > p:first-child { display: none !important; }
120 #xwikicontent > p:empty { display: none !important; }
121 ## Fusszeile: Tags + "Gefaellt mir" + "Erstellt von / uebersetzt von" ausblenden
122 #xdocTags, .doc-tags, .like-container, .xdocCreation { display: none !important; }
123 .intra-wrap { width: 90%; max-width: 90%; margin: 0 auto; }
124 .intra-ticker {
125 display: flex; align-items: stretch; height: 38px;
126 background: #c0392b; margin-bottom: 20px; overflow: hidden; border-radius: 8px;
127 }
128 .intra-ticker-label {
129 flex: 0 0 auto; display: flex; align-items: center;
130 background: #922b21; color: #fff !important; text-decoration: none;
131 font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
132 padding: 0 18px; white-space: nowrap;
133 }
134 .intra-ticker-viewport { flex: 1 1 auto; position: relative; overflow: hidden; }
135 .intra-ticker-date {
136 flex: 0 0 auto; display: flex; align-items: center;
137 color: #ffd7d0 !important; font-size: 13px; font-weight: 700;
138 padding: 0 6px 0 18px; white-space: nowrap;
139 }
140 .intra-ticker-track {
141 position: absolute; top: 0; left: 100%; height: 100%;
142 display: flex; align-items: center; white-space: nowrap;
143 color: #fff !important; text-decoration: none; font-size: 14px; font-weight: 600;
144 padding: 0 18px;
145 animation: intra-ticker-scroll 22s linear infinite;
146 }
147 .intra-ticker-track:hover { animation-play-state: paused; text-decoration: underline; }
148 @keyframes intra-ticker-scroll {
149 from { left: 100%; }
150 to { left: -100%; }
151 }
152 .intra-cols { display: flex; gap: 20px; align-items: stretch; }
153 .intra-main { flex: 2 1 0; min-width: 0; }
154 .intra-side { flex: 1 1 0; display: flex; flex-direction: column; gap: 16px; }
155 .intra-hero {
156 position: relative; width: 100%; min-height: 360px; border-radius: 14px;
157 overflow: hidden; background: #223; background-size: cover; background-position: center;
158 box-shadow: 0 6px 18px rgba(0,0,0,.15); text-decoration: none; display: block;
159 transition: transform .15s ease, box-shadow .15s ease;
160 }
161 .intra-hero:hover {
162 transform: translateY(-3px);
163 box-shadow: 0 12px 28px rgba(0,0,0,.22);
164 }
165 .intra-hero:hover .intra-btn { filter: brightness(1.08); }
166 .intra-hero::after {
167 content: ""; position: absolute; inset: 0;
168 background: linear-gradient(180deg, rgba(0,0,0,0) 30%, rgba(0,0,0,.75) 100%);
169 }
170 .intra-hero-body { position: absolute; left: 0; bottom: 0; z-index: 2; padding: 28px; color: #fff; }
171 .intra-chip {
172 display: inline-block; background: #e74c3c; color: #fff; font-weight: 700;
173 font-size: 12px; letter-spacing: .08em; padding: 4px 12px; border-radius: 20px; text-transform: uppercase;
174 }
175 .intra-hero-date { opacity: .85; font-size: 13px; margin: 14px 0 4px; }
176 .intra-hero h2 { color: #fff; margin: 4px 0 16px; font-size: 30px; line-height: 1.15; max-width: 90%; }
177 .intra-btn {
178 display: inline-block; background: #27ae60; color: #fff !important; text-decoration: none;
179 padding: 9px 20px; border-radius: 24px; font-weight: 600; font-size: 14px;
180 }
181 .intra-btn:hover { filter: brightness(1.08); }
182 .intra-apps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
183 .intra-app {
184 display: flex; flex-direction: column; justify-content: space-between;
185 border-radius: 10px; padding: 12px 12px 10px; min-height: 84px; color: #fff !important;
186 text-decoration: none; transition: transform .15s ease, box-shadow .15s ease;
187 }
188 .intra-app:hover { transform: translateY(-2px); box-shadow: 0 6px 14px rgba(0,0,0,.18); }
189 .intra-app-ic { font-size: 22px; line-height: 1; }
190 .intra-app-ic .fa { color: #fff; }
191 .intra-app-lbl { font-size: 13px; font-weight: 600; margin-top: 8px; }
192 .intra-tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
193 .intra-side-fn {
194 border: 2px dashed #cbd3dc; border-radius: 12px; padding: 20px; min-height: 120px;
195 display: flex; flex-direction: column; align-items: center; justify-content: center;
196 color: #8a97a6; text-align: center; font-size: 13px;
197 }
198 .intra-widget { background: #fff; border: 0.5px solid #e2e6ea; border-radius: 12px; padding: 16px 18px; box-shadow: 0 3px 12px rgba(0,0,0,.06); margin-top: 35px; }
199 .intra-widget-h { font-size: 14px; font-weight: 700; color: #16324f; margin-bottom: 10px; }
200 .intra-cal-link { color: #16324f; text-decoration: none; transition: color .15s ease; }
201 .intra-cal-link:hover { color: #2c6fbb; }
202 .intra-tagcloud { line-height: 2; }
203 .intra-tag { display: inline-block; margin: 0 9px 4px 0; color: #2c6fbb; text-decoration: none; }
204 .intra-tag:hover { text-decoration: underline; }
205 .intra-cal-list { display: flex; flex-direction: column; }
206 .intra-cal-item { display: flex; gap: 10px; align-items: baseline; padding: 7px 0; border-bottom: 1px solid #eef1f4; text-decoration: none; }
207 .intra-cal-item:last-child { border-bottom: 0; }
208 .intra-cal-item:hover .intra-cal-title { text-decoration: underline; }
209 .intra-cal-date { flex: 0 0 auto; font-size: 12px; font-weight: 700; color: #2c6fbb; min-width: 52px; letter-spacing: .02em; }
210 .intra-cal-title { font-size: 13px; color: #16324f; }
211 .intra-cal-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; align-self: center; box-shadow: 0 0 0 1px rgba(0,0,0,.06) inset; }
212 .intra-cal-empty { color: #8a97a6; font-size: 13px; }
213 .intra-tile {
214 display: flex; background: #fff; border-radius: 12px; overflow: hidden;
215 box-shadow: 0 3px 12px rgba(0,0,0,.10); text-decoration: none; color: #1a1a1a; min-height: 128px;
216 transition: transform .15s ease, box-shadow .15s ease;
217 }
218 .intra-tile:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(0,0,0,.15); }
219 .intra-tile-txt { flex: 1 1 auto; padding: 16px 18px; }
220 .intra-tile-txt h3 { margin: 6px 0 6px; font-size: 17px; color: #16324f; }
221 .intra-tile-ex { font-size: 13px; color: #555; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
222 .intra-tile-date { font-size: 12px; color: #8a8a8a; margin-top: 10px; }
223 .intra-mini-chip { display:inline-block; font-size: 11px; font-weight: 700; color:#2c6fbb; letter-spacing:.05em; text-transform: uppercase; }
224 .intra-tile-img { flex: 0 0 40%; background-size: cover; background-position: center; background-color: #dde3ea; }
225 .intra-h { font-size: 15px; font-weight: 700; color: #16324f; margin: 26px 0 12px; }
226 @media (max-width: 860px) {
227 .intra-cols { flex-direction: column; }
228 .intra-apps { grid-template-columns: repeat(4, 1fr); }
229 .intra-tiles { grid-template-columns: 1fr; }
230 }
231 /* Aussenhuelle faengt den 3D-Ueberstand ab -> kein Scrollbalken-Flackern */
232 .intra-flip-outer { overflow: hidden; padding: 8px 12px 18px; margin-top: 24px; }
233 .intra-flip { perspective: 1600px; }
234 .intra-flip-inner {
235 position: relative;
236 transform-style: preserve-3d;
237 transition: transform .6s cubic-bezier(.2,.7,.2,1);
238 transition-delay: .12s; /* kein Flip beim blossen Vorbeiziehen */
239 }
240 .intra-flip.is-back .intra-flip-inner { transform: rotateY(180deg); }
241
242 .intra-flip-face {
243 -webkit-backface-visibility: hidden; backface-visibility: hidden;
244 box-sizing: border-box;
245 background: #fff; border: .5px solid #e2e6ea; border-radius: 12px;
246 box-shadow: 0 3px 12px rgba(0,0,0,.06); padding: 16px 18px;
247 }
248 .intra-flip-front { position: relative; min-height: 250px; } /* gibt die Hoehe vor */
249 .intra-flip-back { position: absolute; inset: 0; transform: rotateY(180deg); overflow: auto; }
250
251 /* Rueckseite darf nicht durch die Vorderseite hindurch klickbar sein */
252 .intra-flip-back { pointer-events: none; }
253 .intra-flip.is-back .intra-flip-back { pointer-events: auto; }
254 .intra-flip.is-back .intra-flip-front { pointer-events: none; }
255
256 .intra-flip-hint {
257 position: absolute; top: 12px; right: 14px;
258 font-size: 10px; color: #8a97a6; background: #f2f5f8;
259 border: 1px solid #e2e6ea; padding: 2px 8px; border-radius: 20px;
260 pointer-events: none;
261 }
262 </style>
263
264 <div class="intra-wrap">
265
266 ## ----- LAUFSCHRIFT: neuester Post mit Kategorie "Breaking News" -----
267 #if ($breakingDoc)
268 <div class="intra-ticker">
269 <a class="intra-ticker-label" href="$breakingURL">$escapetool.xml($breakingCategory)</a>
270 #if ($breakingDate)<span class="intra-ticker-date">$datetool.format('dd.MM.yyyy', $breakingDate)</span>#end
271 <div class="intra-ticker-viewport">
272 <a class="intra-ticker-track" href="$breakingURL">$escapetool.xml($breakingTitle)#if($breakingText != '') — $escapetool.xml($breakingText)#end</a>
273 </div>
274 </div>
275 #end
276
277 <div class="intra-cols">
278
279 ## ===== LINKE SPALTE: Hero + 4 Blog-Kacheln =====
280 <div class="intra-main">
281
282 ## ----- HERO (grosser TOP-Post) -----
283 #if ($heroDoc)
284 <a class="intra-hero" href="$heroDoc.getURL('view')" style="#if($heroImg != '')background-image: url('$heroImg');#end">
285 <div class="intra-hero-body">
286 <span class="intra-chip">$escapetool.xml($heroCategory)</span>
287 #if ($heroDate)<div class="intra-hero-date">$datetool.format('dd. MMMM yyyy', $heroDate)</div>#end
288 <h2>$escapetool.xml($heroTitle)</h2>
289 <span class="intra-btn">Weiterlesen</span>
290 </div>
291 </a>
292 #else
293 <div class="intra-hero"><div class="intra-hero-body"><h2>Noch kein Blog-Beitrag</h2></div></div>
294 #end
295
296 ## ----- 4 BLOG-KACHELN (2 x 2), direkt unter dem Hero -----
297 <div class="intra-h">Aktuelles</div>
298 <div class="intra-tiles">
299 #foreach ($pn in $tilePosts)
300 #set ($td = $xwiki.getDocument($pn))
301 #set ($to = $td.getObject('Blog.BlogPostClass'))
302 #set ($tImg = '')
303 #foreach ($att in $td.getAttachmentList())
304 #if ($tImg == '' && $att.getMimeType().startsWith('image/'))
305 #set ($tImg = $td.getAttachmentURL($att.getFilename()))
306 #end
307 #end
308 #set ($tEx = "$!to.getValue('extract')")
309 #set ($tCat = '')
310 #set ($tcats = $to.getValue('category'))
311 #if ($tcats && $tcats.size() > 0)
312 #set ($fc = "$tcats.get(0)")
313 #set ($tCat = $fc.substring($mathtool.add($fc.lastIndexOf('.'), 1)))
314 #end
315 #set ($tDate = $to.getValue('publishDate'))
316 <a class="intra-tile" href="$td.getURL('view')">
317 <div class="intra-tile-txt">
318 #if ($tCat != '')<span class="intra-mini-chip">$escapetool.xml($tCat)</span>#end
319 <h3>$escapetool.xml($td.getPlainTitle())</h3>
320 <div class="intra-tile-ex">$escapetool.xml($tEx)</div>
321 #if ($tDate)<div class="intra-tile-date">$datetool.format('dd.MM.yyyy', $tDate)</div>#end
322 </div>
323 <div class="intra-tile-img" style="#if($tImg != '')background-image: url('$tImg');#end"></div>
324 </a>
325 #end
326 </div>
327 </div>
328
329 ## ===== RECHTE SPALTE: 12 App-Buttons + Platz fuer weitere Funktion =====
330 <div class="intra-side">
331
332 ## ----- 12 APP-BUTTONS -----
333 <div class="intra-apps">
334 #foreach ($app in $apps)
335 #set ($href = '')
336 #if ("$!app.ref" != '')
337 #set ($href = $xwiki.getURL($app.ref))
338 #elseif ("$!app.url" != '')
339 #set ($href = $app.url)
340 #end
341 <a class="intra-app" style="background: $app.color;"#if($href != '') href="$href"#end>
342 <span class="intra-app-ic"><span class="fa fa-$app.icon" aria-hidden="true"></span></span>
343 <span class="intra-app-lbl">$escapetool.xml($app.label)</span>
344 </a>
345 #end
346 </div>
347
348 ## ----- NAECHSTE TERMINE (Mocca Calendar) / RUECKSEITE: TAGCLOUD -----
349 <div class="intra-flip-outer">
350 <div class="intra-flip" id="intra-flip-side">
351 <div class="intra-flip-inner">
352
353 <!-- VORDERSEITE: Naechste Termine -->
354 <div class="intra-flip-face intra-flip-front">
355 <div class="intra-widget-h"><a class="intra-cal-link" href="$xwiki.getURL('MoccaCalendar.WebHome', 'view')">Nächste Termine</a></div>
356 <div class="intra-cal-list">
357 #set ($now = $datetool.date)
358 ## ---- Kalenderfarben einmalig laden: Event-Elternseite (= Kalender) -> Farbe/Titel ----
359 #set ($calXwql = "select doc.fullName, calendar.color, calendar.title from Document doc, doc.object(MoccaCalendar.MoccaCalendarClass) calendar")
360 #set ($calResults = $services.query.xwql($calXwql).execute())
361 #set ($calColorMap = {})
362 #set ($calTitleMap = {})
363 #foreach ($cr in $calResults)
364 #set ($discard = $calColorMap.put("$cr.get(0)", "$!cr.get(1)"))
365 #set ($discard = $calTitleMap.put("$cr.get(0)", "$!cr.get(2)"))
366 #end
367 #set ($defaultCalColor = '#8a97a6')
368 #set ($evtXwql = "from doc.object(MoccaCalendar.MoccaCalendarEventClass) as event where event.startDate >= :now and doc.hidden = false order by event.startDate asc")
369 #set ($evtNames = $services.query.xwql($evtXwql).bindValue('now', $now).setLimit(6).execute())
370 #if ($evtNames && $evtNames.size() > 0)
371 #foreach ($en in $evtNames)
372 #set ($ed = $xwiki.getDocument($en))
373 #set ($eo = $ed.getObject('MoccaCalendar.MoccaCalendarEventClass'))
374 #set ($eStart = $eo.getValue('startDate'))
375 #set ($eAllDay = $eo.getValue('allDay'))
376 #set ($eTitle = $ed.getPlainTitle())
377 #if ($eTitle == '')#set ($eTitle = "$!eo.getValue('title')")#end
378 ## Kalender der Elternseite ermitteln (Events liegen als Kind-Seite unter ihrem Kalender)
379 #set ($eParent = "$!ed.getParent()")
380 #set ($eColor = $calColorMap.get($eParent))
381 #if (!$eColor || $eColor == '')
382 #set ($eColor = $defaultCalColor)
383 #end
384 #set ($eCalName = $calTitleMap.get($eParent))
385 #if (!$eCalName || $eCalName == '')
386 #set ($eCalName = $xwiki.getDocument($eParent).getPlainTitle())
387 #end
388 <a class="intra-cal-item" href="$ed.getURL('view')">
389 <span class="intra-cal-dot" style="background: $escapetool.xml($eColor);" title="$escapetool.xml($eCalName)"></span>
390 <span class="intra-cal-date">#if($eStart)$datetool.format('dd.MM.', $eStart)#if("$!eAllDay" != '1') $datetool.format('HH:mm', $eStart)#end#end</span>
391 <span class="intra-cal-title">$escapetool.xml($eTitle)</span>
392 </a>
393 #end
394 #else
395 <span class="intra-cal-empty">Keine anstehenden Termine.</span>
396 #end
397 </div>
398 </div>
399
400 <!-- RUECKSEITE: Tagcloud -->##
401 <div class="intra-flip-face intra-flip-back">##
402 <div class="intra-widget-h">Beliebte Themen</div>##
403 #set ($tagMap = $xwiki.tag.getTagCount())##
404 #if ($tagMap && $tagMap.size() > 0)##
405 #set ($top = [])##
406 #set ($maxCnt = 1)##
407 #set ($minCnt = 999999)##
408 #set ($tagCount = 0)##
409 #foreach ($e in $collectiontool.sort($tagMap.entrySet(), ['value:desc']))##
410 #if ($tagCount >= 40)#break#end##
411 #if ($e.key.toLowerCase() != 'id')##
412 #set ($discard = $top.add($e.key))##
413 #set ($tagCount = $mathtool.add($tagCount, 1))##
414 #if ($e.value > $maxCnt)#set ($maxCnt = $e.value)#end##
415 #if ($e.value < $minCnt)#set ($minCnt = $e.value)#end##
416 #end##
417 #end##
418 #set ($span = $mathtool.max(1, $mathtool.sub($maxCnt, $minCnt)))##
419 #set ($alpha = $collectiontool.sort($top))##
420 <div class="intra-tagcloud">##
421 #foreach ($tagName in $top)##
422 #set ($cnt = $tagMap.get($tagName))##
423 #set ($lvl = $mathtool.round($mathtool.div($mathtool.mul($mathtool.sub($cnt, $minCnt), 4), $span)))##
424 #set ($ord = $alpha.indexOf($tagName))##
425 <a class="intra-tag intra-tag-l${lvl}" style="order: ${ord};"##
426 href="$xwiki.getURL('Main.Tags', 'view', "do=viewTag&tag=$escapetool.url($tagName)")"##
427 title="$escapetool.xml($tagName): $cnt Seiten">##
428 <span class="intra-tag-name">$escapetool.xml($tagName)</span><span class="intra-tag-cnt">$cnt</span>##
429 </a>##
430 #end##
431 </div>##
432 #else##
433 <div class="intra-tagcloud"><span class="intra-cal-empty">Noch keine Tags vergeben.</span></div>##
434 #end##
435 </div>##
436
437 </div>
438 </div>
439 </div>
440
441 </div>
442
443 </div>
444 </div>
445 <script>
446 (function(){
447 var box = document.getElementById('intra-flip-side');
448 if(!box){ return; }
449 var hoverCapable = !!(window.matchMedia && window.matchMedia('(hover: hover)').matches);
450 ## Letzte bekannte Maus-Y-Position global mitverfolgen, um beim Betreten der Karte
451 ## die Bewegungsrichtung zu kennen (Y waechst nach unten -> "von unten" = Y wird kleiner).
452 var lastY = null;
453 document.addEventListener('mousemove', function(e){ lastY = e.clientY; }, {passive:true});
454 box.addEventListener('mouseenter', function(e){
455 if (!hoverCapable) { return; }
456 var enteredFromBelow = (lastY !== null && e.clientY < lastY);
457 if (enteredFromBelow) {
458 box.classList.toggle('is-back');
459 }
460 lastY = e.clientY;
461 });
462 box.addEventListener('click', function(e){
463 if(e.target.closest('a')){ return; }
464 if(hoverCapable){ return; }
465 box.classList.toggle('is-back');
466 });
467 })();
468 </script>
469
470 {{/html}}
471 {{/velocity}}