1<!DOCTYPE html> 2<html mt-scroll-padding> 3<head> 4
4<script>window.prerenderReady = false;</script>
4 5 6 <base href="/"> 7 8 <!-- 9 Bootstrap-Daten vorladen. Ohne das ist der kritische Pfad streng serialisiert: 10 das 359-KB-Bundle muss erst geladen UND ausgewertet sein (~855 ms), bevor 11 app.js den ersten API-Request absetzt; localizations und layouts folgen dann 12 nacheinander (~1.253 ms, bis dann gerendert werden kann). 13 14 Hier laufen dieselben Requests ab ~10 ms parallel zum Bundle-Download. Die 15 Antworten landen in window.__preload, gekeyt auf exakt die URL, die Angular 16 spaeter anfragt. app.js liest den Eintrag direkt, localizations und layouts 17 holt der $httpBackend-Decorator in app.preload.js ab. 18 19 Die Sprache wird nicht geraten, sondern aus der configuration-Antwort 20 abgeleitet (gleiche Reihenfolge wie applyConfiguration in app.js), deshalb 21 zwei Wellen statt einer. 22 23 Faellt hier irgendetwas aus (kein fetch, Netzwerkfehler, Exception), bleibt 24 window.__preload leer bzw. der Eintrag verschwindet -- die App laedt dann 25 genau wie vorher. Der Shim darf nie der Grund sein, dass die Seite nicht startet. 26 --> 27
27<script> 28 (function () { 29 'use strict'; 30 31 if (!window.fetch || !window.Promise) { return; } 32 33 var store = window.__preload = {}; 34 35 // key = relative URL wie Angular sie anfragt, geladen wird absolut 36 function preload(key) { 37 var pending = fetch('/' + key, { credentials: 'same-origin', headers: { 'Accept': 'application/json' } }) 38 .then(function (response) { 39 if (!response.ok) { throw new Error(response.status); } 40 return response.json(); 41 }); 42 43 pending['catch'](function () { delete store[key]; }); 44 store[key] = pending; 45 46 return pending; 47 } 48 49 function resolveLanguage(languages) { 50 var i; 51 52 if (!languages || !languages.length) { return null; } 53 54 function known(code) { 55 for (var j = 0; j < languages.length; j++) { 56 if (code && languages[j].code === code) { return code; } 57 } 58 59 return null; 60 } 61 62 // Zuerst das Sprachsegment der URL: der Root-State ist '/{languageCode}/', 63 // und validateLanguage() in main.controller.js laesst die URL ueber Cookie 64 // und Default gewinnen. Das ist also die Sprache, mit der layouts und 65 // localizations am Ende tatsaechlich geladen werden. 66 var segment = /^\/([^\/?#]+)/.exec(location.pathname); 67 var fromUrl = known(segment ? segment[1] : null); 68 69 if (fromUrl) { return fromUrl; } 70 71 // Danach Cookie, Default, erste Sprache -- wie applyConfiguration() in app.js 72 var cookie = /(?:^|;\s*)_cms_lang=([^;]*)/.exec(document.cookie); 73 var fromCookie = known(cookie ? decodeURIComponent(cookie[1]) : null); 74 75 if (fromCookie) { return fromCookie; } 76 77 for (i = 0; i < languages.length; i++) { 78 if (languages[i].isDefault) { return languages[i].code; } 79 } 80 81 return languages[0].code; 82 } 83 84 // Bisher standen die Font-Hashes fest verdrahtet im <head>, waehrend die 85 // tatsaechliche @font-face-URL zur Laufzeit aus den Styling-Settings gebaut 86 // wird (app.styling.js -> generateFontFace). Zwei Quellen fuer dieselbe URL: 87 // sobald im CMS die Schrift getauscht wird, zeigt der Preload ins Leere. 88 // Jetzt kommt beides aus derselben Quelle -- und der Preload startet bei 89 // ~70 ms statt das @font-face erst nach dem Bootstrap bei ~900 ms zu greifen. 90 function preloadFonts(styling) { 91 if (!styling || !styling.fonts) { return; } 92 93 var roles = ['regular', 'bold', 'headingsRegular', 'headingsBold']; 94 var types = { woff2: 'font/woff2', woff: 'font/woff', ttf: 'font/ttf' }; 95 var seen = {}; 96 97 for (var i = 0; i < roles.length; i++) { 98 var wrapper = styling.fonts[roles[i]]; 99 100 if (!wrapper) { continue; } 101 102 // gleiche Praeferenz wie generateFontFace: der Browser nimmt aus der 103 // src-Liste das erste Format, das er unterstuetzt 104 var format = wrapper.woff2 ? 'woff2' : (wrapper.woff ? 'woff' : (wrapper.ttf ? 'ttf' : null)); 105 106 if (!format || !wrapper[format].fileHash) { continue; } 107 108 var href = '/api/static/fonts/' + wrapper[format].fileHash + wrapper[format].extension; 109 110 if (seen[href]) { continue; } 111 seen[href] = true; 112 113 var link = document.createElement('link'); 114 link.rel = 'preload'; 115 link.as = 'font'; 116 link.type = types[format]; 117 link.href = href; 118 link.crossOrigin = 'anonymous'; 119 document.head.appendChild(link); 120 } 121 } 122 123 try { 124 preload('api/live/configuration').then(function (configuration) { 125 try { 126 preloadFonts(configuration.styling); 127 128 var languageCode = resolveLanguage(configuration.languages); 129 130 if (languageCode) { 131 preload('api/live/localizations/' + languageCode); 132 preload('api/live/layouts/' + languageCode); 133 } 134 } 135 catch (error) { /* App laedt normal weiter */ } 136 }, function () { /* App laedt normal weiter */ }); 137 } 138 catch (error) { /* App laedt normal weiter */ } 139 })(); 140 </script>
140 141 <title>{{ ngMeta['og:title'] }}</title> 142 143 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 144 <meta charset="utf-8" /> 145 <meta name="viewport" content="width=device-width, initial-scale=1" /> 146 <meta name="robots" content="{{ ngMeta['robots'] }}"> 147 <meta name="description" content="{{ ngMeta['description'] }}" /> 148 <meta name="keywords" content="{{ ngMeta['keywords'] }}" /> 149 <meta name="author" content="dgtl.ai GmbH" /> 150 <meta name="geo.region" content="DE-BE" /> 151 <meta name="geo.placename" content="Berlin" /> 152 153 <!-- Resource Hints für Performance --> 154 <link rel="preconnect" href="https://consent.cookiebot.com" /> 155 <link rel="preload" href="libs/css/style-e132c28.css" as="style" onload="this.onload=null;this.rel='stylesheet'" /> 156 <noscript><link rel="stylesheet" href="libs/css/style-e132c28.css" /></noscript> 157 <!-- Font-Preloads setzt der Shim oben aus den Styling-Settings, damit sie nicht 158 mit fest verdrahteten Hashes auseinanderlaufen koennen. --> 159 160 <!-- Open Graph --> 161 <meta property="og:site_name" content="dgtl.ai" /> 162 <meta property="og:type" content="{{ ngMeta['og:type'] }}" /> 163 <meta property="og:url" content="{{ ngMeta['og:url'] }}" /> 164 <meta property="og:locale" content="{{ ngMeta['og:locale'] }}" /> 165 <meta property="og:title" content="{{ ngMeta['og:title'] }}" /> 166 <meta property="og:description" content="{{ ngMeta['og:description'] }}" /> 167 <meta property="og:image" content="{{ ngMeta['og:image'] }}" /> 168 <meta property="og:image:width" content="1200" /> 169 <meta property="og:image:height" content="630" /> 170 171 <!-- Twitter / X Card --> 172 <meta name="twitter:card" content="summary_large_image" /> 173 <meta name="twitter:site" content="@dgtlai" /> 174 <meta name="twitter:title" content="{{ ngMeta['og:title'] }}" /> 175 <meta name="twitter:description" content="{{ ngMeta['description'] }}" /> 176 <meta name="twitter:image" content="{{ ngMeta['og:image'] }}" /> 177 178 <!-- Canonical & hreflang dynamisch per JS gesetzt (siehe unten) --> 179 <!-- MS / Theme --> 180 <meta name="msapplication-TileColor" content="#ffffff"> 181 <meta name="msapplication-TileImage" content="https://www.dgtl.ai/api/live/resources/49c1a410-71e8-c071-d853-0602b3c8fd59.png"> 182 <meta name="theme-color" content="#ffffff"> 183 184 <link rel="shortcut icon" href="/api/static/favicon/favicon.ico"> 185 <link rel="apple-touch-icon" sizes="57x57" href="/api/static/favicon/apple-icon-57x57.png"> 186 <link rel="apple-touch-icon" sizes="60x60" href="/api/static/favicon/apple-icon-60x60.png"> 187 <link rel="apple-touch-icon" sizes="72x72" href="/api/static/favicon/apple-icon-72x72.png"> 188 <link rel="apple-touch-icon" sizes="76x76" href="/api/static/favicon/apple-icon-76x76.png"> 189 <link rel="apple-touch-icon" sizes="114x114" href="/api/static/favicon/apple-icon-114x114.png"> 190 <link rel="apple-touch-icon" sizes="120x120" href="/api/static/favicon/apple-icon-120x120.png"> 191 <link rel="apple-touch-icon" sizes="144x144" href="/api/static/favicon/apple-icon-144x144.png"> 192 <link rel="apple-touch-icon" sizes="152x152" href="/api/static/favicon/apple-icon-152x152.png"> 193 <link rel="apple-touch-icon" sizes="180x180" href="/api/static/favicon/apple-icon-180x180.png"> 194 <link rel="icon" type="image/png" sizes="192x192" href="/api/static/favicon/android-icon-192x192.png"> 195 <link rel="icon" type="image/png" sizes="32x32" href="/api/static/favicon/favicon-32x32.png"> 196 <link rel="icon" type="image/png" sizes="96x96" href="/api/static/favicon/favicon-96x96.png"> 197 <link rel="icon" type="image/png" sizes="16x16" href="/api/static/favicon/favicon-16x16.png"> 198 <link rel="manifest" href="/api/static/favicon/manifest.json" crossorigin="use-credentials"> 199 200 <link rel="sitemap" type="application/xml" href="/api/live/sitemaps/de/sitemap.xml" /> 201
201<script type="application/ld+json"> 202 { 203 "@context": "https://schema.org", 204 "@type": "Organization", 205 "name": "dgtl.ai GmbH", 206 "url": "https://www.dgtl.ai", 207 "logo": "https://www.dgtl.ai/api/live/resources/c838e0d8-6fa2-94a4-e67a-385fc6f75973.png", 208 "contactPoint": { 209 "@type": "ContactPoint", 210 "email": "[email protected]", 211 "contactType": "customer service", 212 "availableLanguage": ["German", "English"] 213 }, 214 "address": { 215 "@type": "PostalAddress", 216 "streetAddress": "Leipziger Platz 10", 217 "addressLocality": "Berlin", 218 "postalCode": "10117", 219 "addressCountry": "DE" 220 }, 221 "sameAs": [ 222 "https://www.linkedin.com/company/dgtl-ai/" 223 ] 224 } 225 </script>
225 226
226<script type="application/ld+json" id="faq-schema"></script>
226 227
227<script type="application/ld+json" id="breadcrumb-schema"></script>
227 228
228<script type="application/ld+json" id="webpage-schema"></script>
228 229
229<script type="application/ld+json" id="article-schema"></script>
229 230 231 <style type="text/css" ng-bind="gcss"></style> 232 <style type="text/css" ng-bind="ccss"></style> 233</head> 234 235<body ng-cloak> 236 <section class="mt-wrapper" ui-view="main"></section> 237 <div cookie-popup-banner config="cookiePopupConfig"></div> 238
238<script nomodule> 239 var legacyBrowser = true; 240 </script>
240 241
241<script src="libs/js/app-e132c28.min.js" type="text/javascript" async></script>
241 242</body> 243</html>
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.