1/*@cc_on 2 (function(f) { 3 window.setTimeout = f(window.setTimeout); // overwrites the global function! 4 window.setInterval = f(window.setInterval); // overwrites the global function! 5 })(function(f) { 6 return function(c, t) { 7 var a = [].slice.call(arguments, 2); // gathers the extra args 8 return f(function() { 9 c.apply(this, a); // passes them to your function 10 }, t); 11 }; 12 }); 13 @*/ 14 15(function ($) { 16 $(function () { 17 // TOP FLOP 18 $('.dropdown .current-selected').on('click', function (event) { 19 event.stopPropagation(); 20 $('.dropdown-options.open').removeClass('open'); 21 $(this).next().addClass('open'); 22 }); 23 24 // on blur --> close all dropdowns 25 $(document).on('click', function () { 26 $('.dropdown-options.open').removeClass('open'); 27 }); 28 29 $('.dropdown .dropdown-options li').on('click', function () { 30 if (!$(this).hasClass('selected')) { 31 $(this).parent().find('.selected').removeClass('selected'); 32 $(this).addClass('selected'); 33 34 if ($(this).parents('.top-flop').length) { //top-flop specific 35 var element = $(this).parents('.top-flop').find('.top-flop-container'); 36 var gridID = $(this).parents('.top-flop').data('contentId'); 37 var marketID = $(this).data('id'); 38 var title = $(this).find('h4').text(); 39 var last = $(this).find('.last').text(); 40 var changePerc = $(this).find('.changePerc').text(); 41 42 $(this).parents('.dropdown').find('.current-selected h4').text(title); 43 $(this).parents('.dropdown').find('.current-selected .last').text(last); 44 $(this).parents('.dropdown').find('.current-selected .changePerc').text(changePerc); 45 46 getTopFlopContent(marketID, element, gridID); 47 } 48 if ($(this).parents('.exchange-select').length) { //exchange select; currently used in share/currency/resource header section to change exchange/price 49 var title = $(this).find('a').text(); 50 $(this).parents('.dropdown').find('.current-selected h4').text(title); 51 } 52 if ($(this).parents('.event-type-dropdown').length) { //something for events 53 var title = $(this).find('p').text(); 54 $(this).parents('.dropdown').find('.current-selected p').text(title); 55 } 56 if ($(this).parents('.share-dropdown').length) { //set selected dropdown option for market-news share-search 57 var title = $(this).find('p').text(); 58 $(this).parents('.dropdown').find('.current-selected p').text(title); 59 } 60 if ($(this).parents('.header-charts').length) { //charts for all indices in header area 61 var title = $(this).find('h4').text(); 62 var element = $(this).parents('.header-charts').find('.header-chart-image'); 63 var marketID = $(this).data('id'); 64 $(this).parents('.dropdown').find('.current-selected h4').text(title); 65 66 getHeaderChartImage(marketID, element); 67 } 68 if ($(this).parents('.stockexchange-market-chart').length) { //stockexchangepage - charts for all markets 69 var title = $(this).find('h4').text(); 70 var element = $(this).parents('.stockexchange-market-chart').find('.market-chart-container'); 71 var marketID = $(this).data('id'); 72 $(this).parents('.dropdown').find('.current-selected h4').text(title); 73 74 var href = $(this).data('link'); 75 $('.stockexchange-market-chart .more-btn a').attr('href', href); 76 77 getStockExchangeMarketCharts(marketID, element); 78 } 79 if ($(this).parents('.currency-from-dropdown').length || $(this).parents('.currency-to-dropdown').length) { 80 var title = $(this).find('p').text(); 81 $(this).parents('.dropdown').find('.current-selected p').text(title); 82 } 83 if ($(this).parents('.market-shares').length) { //shares in market dropdown 84 var marketID = $(this).data('id'); 85 var element = $(this).parents('.market-shares').find('.market-shares-container'); 86 var gridID = $(this).parents('.market-shares').data('contentId'); 87 88 var title = $(this).find('h4').text(); 89 var last = $(this).find('.last').text(); 90 var changePerc = $(this).find('.changePerc').text(); 91 92 $(this).parents('.dropdown').find('.current-selected h4').text(title); 93 $(this).parents('.dropdown').find('.current-selected .last').text(last); 94 $(this).parents('.dropdown').find('.current-selected .changePerc').text(changePerc); 95 96 getMarketSharesContent(marketID, element, gridID); 97 } 98 } 99 }); 100 101 /*Top-Flop*/ 102 if ($('.top-flop-container').length) { 103 var getTopFlopContent = function (id, element, gridId, url) { 104 if (!url) { 105 if (element.hasClass('ls-market')) { 106 url = 'home/getLSMarketTopFlopContent'; 107 } else { 108 url = 'home/getTopFlopContent'; 109 } 110 } 111 $.ajax({ 112 type: 'POST', 113 url: url, 114 data: { 115 ajax: 1, 116 id: id, 117 gridId: gridId 118 } 119 }) 120 .done(function (response) { 121 element.html(response); 122 }) 123 .fail(function (xhr) { 124 //alert("Error: " + xhr.responseText); 125 }); 126 }; 127 } 128 $('.top-flop').each(function () { 129 var element = $(this).find('.top-flop-container'); 130 var marketID = $(this).data('defaultMarket'); 131 var gridID = $(this).data('contentId'); 132 133 getTopFlopContent(marketID, element, gridID); 134 }); 135 /*Header charts*/ 136 if ($('.header-charts').length) { 137 var getHeaderChartImage = function (id, element, url) { 138 if (!url) { 139 url = 'home/getHeaderChartImage'; 140 } 141 $.ajax({ 142 type: 'POST', 143 url: url, 144 data: { 145 ajax: 1, 146 id: id 147 } 148 }) 149 .done(function (response) { 150 element.html(response); 151 }) 152 .fail(function (xhr) { 153 //alert("Error: " + xhr.responseText); 154 }); 155 }; 156 var element = $(this).find('.header-chart-image'); 157 getHeaderChartImage(15, element); //fixed to atx(db) at the moment 158 } 159 /*Stockexchangepage - market charts*/ 160 if ($('.stockexchange-market-chart').length) { 161 var getStockExchangeMarketCharts = function (id, element, url) { 162 if (!url) { 163 url = 'home/getStockExchangeMarketCharts'; 164 } 165 $.ajax({ 166 type: 'POST', 167 url: url, 168 data: { 169 ajax: 1, 170 id: id 171 } 172 }) 173 .done(function (response) { 174 element.html(response); 175 setChartNavClickHandler(); 176 }) 177 .fail(function (xhr) { 178 //alert("Error: " + xhr.responseText); 179 }); 180 }; 181 $('.stockexchange-market-chart').each(function () { 182 var element = $(this).find('.market-chart-container'); 183 var marketID = $(this).data('defaultMarket'); 184 185 var href = $('.stockexchange-market-chart .selected').data('link'); 186 $('.stockexchange-market-chart .more-btn a').attr('href', href); 187 188 getStockExchangeMarketCharts(marketID, element); 189 }); 190 } 191 /*Shares of market*/ 192 if ($('.market-shares-container').length) { 193 var getMarketSharesContent = function (id, element, gridID, url) { 194 if (!url) { 195 url = 'home/getAllMarketSharesContent'; 196 } 197 $.ajax({ 198 type: 'POST', 199 url: url, 200 data: { 201 ajax: 1, 202 id: id, 203 gridID: gridID 204 } 205 }) 206 .done(function (response) { 207 element.html(response); 208 }) 209 .fail(function (xhr) { 210 //alert("Error: " + xhr.responseText); 211 }); 212 }; 213 } 214 215 // TTWS Push Data 216 var ttPush; 217 218 function startPush(symbolIDs, symbolFIDs) { 219 var securityToken = ""; 220 221 ttPush = new TT.Push({ token: securityToken, tokenCallback: getSecurityToken }); 222 223 ttPush.SetOptions({ 224 'pushurl': 'https://push.ttweb.net/http_push/', 225 'symbolfids': symbolFIDs, 226 'timezone': 'Europe/Vienna', 227 'symbolsnapshot': true, 228 'loglevel': 'none' 229 }); 230 231 ttPush.startBatch(); 232 ttPush.subscribe([{ 233 symbolID: symbolIDs,
234 callback: handlePushMessage, 235 filterFields: { 236 PushType: "Snapshot" 237 } 238 }]); 239 ttPush.endBatch(); 240 241 ttPush.addEventListener('status', function (status) { 242 //console.log('status.statusType: ' + status.statusType + ", status.message: " + JSON.stringify(status.message)); 243 if (status.message.error) { 244 //console.log('status.message.error: ' + status.message.error); 245 } 246 }); 247 } 248 249 function getSecurityToken(tokenSuccessCallback) { 250 $.ajax({ 251 type: 'POST', 252 url: 'home/getSecurityPushToken' 253 }) 254 .done(function (response) { 255 var securityToken = JSON.parse(response)['token']; 256 tokenSuccessCallback(securityToken); 257 }) 258 .fail(function (xhr) { 259 }); 260 } 261 262 // Zerlegt einen Feed-Zeitstempel in Datum und Uhrzeit â die EINE Stelle, die weiss, dass der 263 // Feed nicht konsistent ist: manche Symbole senden "30.07.2026 11:57:00", andere ISO 264 // "2026-07-29T00:00:00". Bis 2026-08-26 stand diese Zerlegung nur im 'full'-Zweig; der 265 // zweite Zweig schnitt mit slice(11) blind eine Uhrzeit heraus und warf alles andere weg â 266 // das KPI-Widget verlor dadurch bei jedem Tick sein Datum. Eine zweite Fassung derselben 267 // Regel ist ein zweiter Kandidat fuer den Fehler, also gibt es sie nur noch hier. 268 // 269 // Rueckgabe: {date:'26.08.2026', date2:'26.08.26', time:'11:30', noTime:false} oder null. 270 // noTime === true heisst: der Feed schickte ein Sitzungsdatum OHNE Uhrzeit (exakt 00:00). 271 // Das ist keine Mitternachts-Notierung, sondern eine fehlende Angabe. 272 function splitFeedStamp(raw) { 273 var v = String(raw == null ? '' : raw); 274 var d = null, t = null, y = null; 275 var iso = v.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}:\d{2})/); 276 if (iso) { 277 d = iso[3] + '.' + iso[2] + '.' + iso[1]; 278 y = iso[1]; 279 t = iso[4]; 280 } else { 281 var de = v.match(/^(\d{2})\.(\d{2})\.(\d{4})[T ]?\s*(\d{2}:\d{2})/); 282 if (de) { 283 d = de[1] + '.' + de[2] + '.' + de[3]; 284 y = de[3]; 285 t = de[4]; 286 } 287 } 288 if (!d) { return null; } 289 return { 290 date: d, 291 // zweistelliges Jahr fuer die Krypto-Kopfzeile (dd.MM.yy) 292 date2: d.slice(0, 6) + y.slice(2), 293 time: t, 294 noTime: t === '00:00' 295 }; 296 } 297 298 // Sortierschluessel '<YYYY><MM><DD><HH><mm>' aus der Form, die splitFeedStamp() liefert 299 // ('dd.mm.yyyy' + 'HH:MM'). Zwoelf Ziffern, lexikographisch vergleichbar â bewusst KEIN 300 // Date-Objekt: der Feed traegt keine Zeitzone, und new Date('28.08.2026') ist je nach 301 // Browser Invalid Date oder eine amerikanisch gelesene Fehldeutung. Ein Stringvergleich 302 // kann beides nicht. 303 function stampSortKey(date, time) { 304 if (!date) { return null; } 305 var t = time || '00:00'; 306 return date.slice(6, 10) + date.slice(3, 5) + date.slice(0, 2) + t.slice(0, 2) + t.slice(3, 5); 307 } 308 309 // Liest den Stempel, den der SERVER in das Element geschrieben hat, zurueck in denselben 310 // Schluessel. Die ausgelieferten Serverformen sind nicht eine, sondern drei: 311 // "31.08.2026, 21:56" Asset/Masthead.ss (assetStamp(), 'd.m.Y, H:i') 312 // "31.08.2026 | 21:56" die zehn Grid-/Header-Templates ('dd.MM.yyyy | HH:mm') 313 // "31.08.2026" assetStamp() bei Feedzeit exakt 00:00 â Datum ohne Uhr 314 // Deshalb ist das Trennzeichen als [^\d]{1,3} offen und die Uhrzeit optional; fuehrender 315 // Whitespace kommt aus den <td>-Zellen. null = nichts Vergleichbares da (leer, 'â', 316 // Platzhalter) â dann greift die Ordnungsregel bewusst NICHT. 317 function parseRenderedStamp(text) { 318 var m = String(text == null ? '' : text).match(/(\d{2})\.(\d{2})\.(\d{4})(?:[^\d]{1,3}(\d{2}):(\d{2}))?/); 319 if (!m) { return null; } 320 return m[3] + m[2] + m[1] + (m[4] || '00') + (m[5] || '00'); 321 } 322 323 // Ist diese Nachricht aelter als das, was die Seite fuer dasselbe Symbol bereits anzeigt? 324 // 325 // Das Gate steht bewusst VOR der ersten Feldbehandlung und verwirft die GANZE Nachricht. 326 // Eine Pruefung im dateTime-Zweig kaeme zu spaet: handlePushMessage schreibt changePercent, 327 // change, last, high, low und volume vorher und bid/ask nachher, der dateTime-Block liegt 328 // mittendrin. Ein `return` dort verschont nur den Stempel â der veraltete Kurs derselben 329 // Nachricht steht dann bereits im DOM, und zwar unter dem NEUEREN Serverdatum. Das ist 330 // schlimmer als gar kein Guard: vorher war das Paar wenigstens stimmig alt und am Datum 331 // erkennbar, so sieht es frisch aus. (Codex-Review 2026-09-01.) 332 // 333 // Referenz ist der SPAETESTE lesbare 'full'-Stempel des Symbols. Rendert eine Seite dasselbe 334 // Symbol zweimal mit verschiedenen Staenden, ist das die konservative Wahl â lieber einen 335 // zweifelhaften Push fallen lassen als ihn ueber den frischesten angezeigten Wert schreiben. 336 // 337 // Nur 'full' traegt ueberhaupt ein Datum im DOM. Seiten, die nur 'time' rendern 338 // (HeaderIndizes.ss, Asset/PriceList.ss, AssetStrip.ss), haben keine Referenz â dort 339 // urteilt das Gate nicht und es aendert sich nichts. 340 function pushIsStale(msg) { 341 var parts = splitFeedStamp(msg.data.dateTime); 342 if (!parts) { return false; } // unlesbarer Feedwert: kein Urteil, nicht verwerfen 343 var newKey = stampSortKey(parts.date, parts.time); 344 var curKey = null; 345 $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-dateTime[data-push-timeformat="full"]').each(function () { 346 var k = parseRenderedStamp($(this).text());
347 if (k !== null && (curKey === null || k > curKey)) { curKey = k; } 348 }); 349 return curKey !== null && newKey < curKey; 350 } 351 352 function handlePushMessage(msg) { 353 //console.log(msg); 354 355 // Ordnungsregel fuer die ganze Nachricht. Ohne dateTime gibt es nichts zu vergleichen â 356 // eine Teilaktualisierung ohne Stempel darf nicht an dieser Regel scheitern. 357 if (typeof msg.data.dateTime != 'undefined' && pushIsStale(msg)) { 358 return; 359 } 360 361 var changeVal = ""; 362 363 if (typeof msg.data.changePercent != 'undefined') { 364 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-changePercent'); 365 366 elements.each(function () { 367 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 368 var val = germanNumberFormat(msg.data.changePercent, decimalPlaces); 369 var rounded = parseFloat(msg.data.changePercent).toFixed(decimalPlaces); 370 if (rounded > 0) { 371 changeVal = "positive"; 372 val = "+" + val; 373 } else if (rounded < 0) { 374 changeVal = "negative"; 375 } else { 376 changeVal = "neutral"; 377 } 378 379 adjustValue($(this), val + "%", true, changeVal); 380 applyPushDirection($(this), rounded); 381 }); 382 } 383 if (typeof msg.data.change != 'undefined') { 384 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-change'); 385 elements.each(function () { 386 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 387 var val = germanNumberFormat(msg.data.change, decimalPlaces); 388 // Die Richtung folgt der Zahl, die DIESES Element zeigt â nicht dem changeVal des 389 // zuletzt iterierten Prozent-Elements (andere Rundung, oder gar keins in der Nachricht). 390 var rounded = parseFloat(msg.data.change).toFixed(decimalPlaces); 391 var ownChangeVal = isNaN(parseFloat(rounded)) ? changeVal 392 : (rounded > 0 ? "positive" : (rounded < 0 ? "negative" : "neutral")); 393 adjustValue($(this), val, true, ownChangeVal); 394 applyPushDirection($(this), rounded); 395 }); 396 } 397 if (typeof msg.data.last != 'undefined') { 398 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-last'); 399 elements.each(function () { 400 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 401 var val = germanNumberFormat(msg.data.last, decimalPlaces); 402 adjustValue($(this), val, true, changeVal); 403 }); 404 } 405 if (typeof msg.data.high != 'undefined') { 406 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-high'); 407 elements.each(function () { 408 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 409 var val = germanNumberFormat(msg.data.high, decimalPlaces); 410 adjustValue($(this), val, true, changeVal); 411 }); 412 } 413 if (typeof msg.data.low != 'undefined') { 414 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-low'); 415 elements.each(function () { 416 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 417 var val = germanNumberFormat(msg.data.low, decimalPlaces); 418 adjustValue($(this), val, true, changeVal); 419 }); 420 } 421 if (typeof msg.data.volume != 'undefined') { 422 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-volume'); 423 elements.each(function () { 424 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 425 var val = germanNumberFormat(msg.data.volume, decimalPlaces); 426 adjustValue($(this), val, true, changeVal); 427 }); 428 } 429 if (typeof msg.data.dateTime != 'undefined') { 430 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-dateTime'); 431 elements.each(function () { 432 var val; 433 if ($(this).data('pushTimeformat') === "full") { 434 // The feed is NOT consistent per symbol: some send "30.07.2026 11:57:00", 435 // others ISO "2026-07-29T00:00:00". The old code assumed the German shape 436 // and cut at index 11, which for ISO kept the "T" and produced 437 // "2026-07-29T| 00:00" on DAX. Normalise the date part first, then use the 438 // same "date, time" shape the server renders so the stamp does not jump 439 // from "30.07.2026, 11:57" to "30.07.2026 | 11:57" on the first push. 440 val = String(msg.data.dateTime); 441 var parts = splitFeedStamp(msg.data.dateTime); 442 var dPart = parts ? parts.date : null, tPart = parts ? parts.time : null; 443 if (dPart) { 444 // Same rule as the server (assetStamp): a feed time of exactly 00:00 is a 445 // session date with no clock, so show the date alone. Without this the 446 // stamp gained a meaningless ", 00:00" the moment the first push landed. 447 val = (tPart === "00:00") ? dPart : (dPart + ", " + tPart); 448 } 449 } else {
450 // Die uebrigen Formate. Bis 2026-08-26 stand hier EIN Zweig fuer drei Templates mit drei 451 // verschiedenen Server-Formaten, und er schnitt mit slice(11) blind eine Uhrzeit heraus: 452 // das KPI-Widget rendert serverseitig "26.08.2026 · 11:30" und stand nach dem ersten Tick 453 // auf "12:29" â Datum weg (gemessen auf prod 2026-08-26). Jetzt spiegelt jeder Formatname 454 // exakt das, was sein Template ausliefert. 455 var fmt = $(this).data('pushTimeformat'); 456 var p = splitFeedStamp(msg.data.dateTime); 457 if (!p) { 458 // Unlesbarer Stempel: lieber den servergerenderten Wert stehen lassen als Muell 459 // hineinschreiben. 460 return; 461 } 462 if (p.noTime) { 463 // Der Feed hat ein Sitzungsdatum OHNE Uhrzeit geschickt â das kommt vor, wenn die 464 // Boerse zu ist. Hier NICHTS anfassen: der Server hat den echten Zeitpunkt aus der 465 // Preiszeile gerendert (z.B. "22:00"), waehrend das gepushte Datum das HEUTIGE 466 // Sitzungsdatum sein kann. Ein Datum hineinzuschreiben wuerde behaupten, der Kurs sei 467 // von heute â eine plausibel aussehende Falschangabe, schlimmer als gar keine. 468 return; 469 } 470 if (fmt === 'date-time') { 471 val = p.date + ' \u00b7 ' + p.time; // ShareKPIWidget.ss: dd.MM.YYYY · HH:mm 472 } else if (fmt === 'date2-time') { 473 val = p.date2 + ' | ' + p.time; // frueher HeaderCrypto.ss (entfernt 2026-09-26); kein Template nutzt es mehr 474 } else { 475 // 'time' und der Alt-Wert 'short'. Der Alias bleibt, weil ttws.js ein statisches Asset 476 // mit ?m=<mtime> ist: zwischen Deploy und Cache-Ablauf treffen alte HTML-Bodies aus dem 477 // Page-Cache auf neues JS, und ohne Alias verloere so ein Stempel jede Aktualisierung. 478 val = p.time; // AssetStrip.ss: HH:mm 479 } 480 } 481 482 adjustValue($(this), val, false, changeVal); 483 }); 484 } 485 if (typeof msg.data.bid != 'undefined') { 486 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-bid'); 487 elements.each(function () { 488 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 489 var val = germanNumberFormat(msg.data.bid, decimalPlaces); 490 adjustValue($(this), val, true, changeVal); 491 }); 492 } 493 if (typeof msg.data.ask != 'undefined') { 494 var elements = $('.tts-push-id-' + msg.data.symbolId + '.tts-push-fid-ask'); 495 elements.each(function () { 496 var decimalPlaces = $(this).data('decimalPlaces') ? $(this).data('decimalPlaces') : 2; 497 var val = germanNumberFormat(msg.data.ask, decimalPlaces); 498 adjustValue($(this), val, true, changeVal); 499 }); 500 } 501 } 502 503 function adjustValue(element, val, doBlink, changeVal) { 504 // blink animation 505 if (doBlink) { 506 var prevVal = element.text(); 507 blink(element, prevVal, val); 508 } 509 510 if (changeVal === "neutral") { 511 val = val.replace("-", ""); 512 } 513 514 var changeColor = false; 515 516 // set text 517 if (element.data("pushFormat") === "brackets") { 518 element.text("("+val+")"); 519 } else { 520 element.text(val); 521 } 522 523 // change color 524 var changeColor = element.data("pushColorchange"); 525 if (changeColor === undefined || changeColor == 1) { 526 changeColor = true; 527 } 528 529 if (changeColor) { 530 if (changeVal !== "") { 531 element.removeClass('positive'); 532 element.removeClass('negative'); 533 } 534 if (changeVal !== "neutral") { 535 element.addClass(changeVal); 536 } 537 } 538 } 539 540 /* Richtungsvertrag (2026-09-18). adjustValue() setzt positive/negative nur am Push-Element; die 541 Richtung, die Farbe, Pfeil und Hintergrund traegt, sitzt je nach Template in einem anderen 542 Vokabular (up/down/flat, pos/neg/flat, shs-*, mkw--*, positive/negative/neutral) und oft an 543 einem VORFAHREN (Chip, MarktJetzt, Artikel-Ticker, KPI-Widget). Ohne Mitschalten stand nach 544 einem Vorzeichenwechsel "+5,14 %" in Rot mit â¼ (prod, 2026-09-18). 545 Das Element, das die Richtung traegt, deklariert sein Vokabular: 546 data-push-dir="<up> <down> [<flat>]". Kein Attribut (altes HTML aus dem Page-Cache) oder 547 weniger als zwei Namen = gar nichts tun, also exakt das bisherige Verhalten. */ 548 function applyPushDirection(element, rounded) { 549 var node = element && element[0]; 550 var v = parseFloat(rounded); 551 if (!node || typeof node.closest !== 'function' || isNaN(v)) { 552 return; 553 } 554 var changeColor = element.data("pushColorchange"); 555 if (!(changeColor === undefined || changeColor == 1)) { 556 return; 557 } 558 var host = node.closest('[data-push-dir]'); 559 if (!host) { 560 return; 561 } 562 var names = String(host.getAttribute('data-push-dir') || '').split(/\s+/).filter(function (n) { return n !== ''; }); 563 if (names.length < 2) { 564 return; 565 } 566 var target = v > 0 ? names[0] : (v < 0 ? names[1] : (names[2] || '')); 567 for (var i = 0; i < names.length; i++) { 568 host.classList.remove(names[i]); 569 } 570 if (target) { 571 host.classList.add(target); 572 } 573 } 574 575 function germanNumberFormat(number, decimalPlaces) { 576 number = parseFloat(number).toFixed(decimalPlaces); 577 var split = number.toString().split('.'); 578 var preComma = split[0]; 579 var postComma = split.length > 1 ? split[1] : ''; 580
581 preComma = preComma.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); 582 583 return preComma + ',' + postComma; 584 } 585 586 function blink(element, prevVal, newVal) { 587 prevVal = prevVal.replace('(', '').replace(')', ''); 588 prevVal = parseFloat(prevVal.replace('.', '').replace(',', '.')); 589 newVal = parseFloat(newVal.replace('.', '').replace(',', '.')); 590 var color = ""; 591 592 if (newVal > prevVal) { 593 color = "push-positive"; 594 } else if (newVal < prevVal) { 595 color = "push-negative"; 596 } 597 598 if (color !== "") { 599 element.addClass(color); 600 setTimeout(function (element, color) { 601 element.removeClass(color); 602 }, 300, element, color); 603 } 604 } 605 606 if ($('.tts-push-data').length) { 607 // fetch needed data 608 var symbolIDs = []; 609 var symbolFIDs = []; 610 611 $('.tts-push-data').each(function () { 612 var symbolID = $(this).data("pushId"); 613 var symbolFID = $(this).data("pushData"); 614 615 // dont add duplicates 616 if (symbolIDs.indexOf(symbolID) == -1) { 617 symbolIDs.push(symbolID); 618 } 619 if (symbolFIDs.indexOf(symbolFID) == -1) { 620 symbolFIDs.push(symbolFID); 621 } 622 }); 623 624 //console.log("symbolIDs", symbolIDs); 625 //console.log("symbolFIDs", symbolFIDs); 626 627 startPush(symbolIDs, symbolFIDs); 628 } 629 }); 630})(jQuery);
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.