Wiki-Quellcode von Home
Zuletzt geändert von Admin am 15.08.2026 00:04
Zeige letzte Bearbeiter
| author | version | line-number | content |
|---|---|---|---|
| 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':'Haupt-Wiki', 'icon':'search', 'ref':'xwiki: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}} |