PageSourceSearch

https://www.mikrometoxos.gr/wp-content/plugins/finance-helper/asse…/front-finance-helper.js?ver=6abfae8d030ee

js mikrometoxos.gr collected 2026-10-02 13:33:06 UTC 19,949 bytes, 495 lines download raw bytes

1document.addEventListener("DOMContentLoaded", () => {
2    if (typeof FinanceHelperData === "undefined" || !FinanceHelperData.apiUrl) {
3        console.warn("FinanceHelperData.apiUrl not defined");
4        return;
5    }
6
7    let apiData = null; // cache the API response
8
9    const fetchData = async () => {
10        if (apiData) return apiData; // already fetched once
11        try {
12            const res = await fetch(FinanceHelperData.apiUrl);
13            const data = await res.json();
14            apiData = data?.["inbroker-transactions"]?.row || [];
15            return apiData;
16        } catch (err) {
17            console.error("Finance Helper API fetch error:", err);
18            return [];
19        }
20    };
21
22    const observer = new IntersectionObserver(async (entries, obs) => {
23        const allData = await fetchData(); // fetch once
24
25        entries.forEach(entry => {
26            if (entry.isIntersecting) {
27                const el = entry.target;
28                const stockSlug = el.getAttribute("data-stock");
29                const span = el.querySelector(".card__finance-stocks-item--up, .card__finance-stocks-item--down") ||
30                    el.querySelector("span");
31
32                if (!stockSlug || !span) return;
33
34                const stock = allData.find(item => item.instrSysName === stockSlug);
35                if (stock && typeof stock.closePrevClosePDelta !== "undefined") {
36                    const stockPrice = (stock.closePrice > 0 ?
37                        stock.closePrevClosePDelta :
38                        (stock.price > 0 ? stock.pricePrevClosePricePDelta : 0));
39
40                    const value = parseFloat(stockPrice);
41                    span.textContent = `${value > 0 ? '+' : ''}${value.toFixed(2)}%`;
42                    span.classList.remove("card__finance-stocks-item--up", "card__finance-stocks-item--down");
43                    span.classList.add(value > 0 ? "card__finance-stocks-item--up" : "card__finance-stocks-item--down");
44                } else {
45                    span.textContent = "N/A";
46                }
47
48                obs.unobserve(el);
49            }
50        });
51    }, {threshold: 0.2});
52
53    document.querySelectorAll(".card__finance-stocks").forEach(el => observer.observe(el));
54
55
56    const quoteBlocks = document.querySelectorAll('.fh-quotes');
57    if (!quoteBlocks.length) return;
58
59    // Fetch data once per page
60    fetch(FinanceHelperData.apiUrl)
61        .then(res => res.json())
62        .then(data => {
63            const rows = data?.['inbroker-transactions']?.row || [];
64
65            quoteBlocks.forEach(block => {
66                const order = block.dataset.order || 'asc';
67                let sorted;
68                
69                // Sort based on order type
70                if (order === 'turnover') {
71                    // Sort by max turnover descending
72                    sorted = [...rows].sort((a, b) => {
73                        const turnoverA = parseFloat(a.totalTurnover) || 0;
74                        const turnoverB = parseFloat(b.totalTurnover) || 0;
75                        return turnoverB - turnoverA;
76                    });
77                } else {
78                    // Sort by PDelta (asc or desc)
79                    sorted = [...rows].sort((a, b) => {
80                        const deltaA = parseFloat(a.pricePrevClosePricePDelta) || 0;
81                        const deltaB = parseFloat(b.pricePrevClosePricePDelta) || 0;
82                        return order === 'desc' ? deltaB - deltaA : deltaA - deltaB;
83                    });
84                }
85
86                // Limit to first 6 for performance
87                const topRows = sorted.slice(0, 6);
88
89                let html, headerHtml;
90                
91                if (order === 'turnover') {
92                    // Turnover mode: show symbol, turnover, delta
93                    headerHtml = `
94                        <div class="fh-quote">
95                            <div class="fh-quote__symbol"><strong>Μετοχή</strong></div>
96                            <div class="fh-quote__turnover"><strong>Τζίρος</strong></div>
97                            <div class="fh-quote__delta"><strong>Μεταβολή</strong></div>
98                        </div>`;
99                    
100                    html = topRows.map(row => {
101                        const deltaValue = parseFloat(row.pricePrevClosePricePDelta).toFixed(3);
102                        const delta = Number(deltaValue).toLocaleStr
102ing('el-GR', {maximumFractionDigits: 2});
103                        const isUp = deltaValue >= 0;
104                        const deltaClass = isUp ? 'fh-quote__delta--up' : 'fh-quote__delta--down';
105                        const sign = isUp ? '+' : '';
106                        const turnover = Number(row.totalTurnover).toLocaleString('el-GR', {maximumFractionDigits: 2});
107
108                        return `
109                            <div class="fh-quote">
110                                <a href="/quote/${row.instrSysName}" class="fh-quote__symbol">${row.instrCode}</a>
111                                <div class="fh-quote__turnover">${turnover} €</div>
112                                <div class="fh-quote__delta ${deltaClass}">${sign}${delta}%</div>
113                            </div>`;
114                    }).join('');
115                } else {
116                    // Asc/Desc mode: show symbol, price, delta (no turnover)
117                    headerHtml = `
118                        <div class="fh-quote">
119                            <div class="fh-quote__symbol"><strong>Μετοχή</strong></div>
120                            <div class="fh-quote__price"><strong>Τιμή</strong></div>
121                            <div class="fh-quote__delta"><strong>Μετ</strong></div>
122                            <div class="fh-quote__delta"><strong>Μετ%</strong></div>
123                        </div>`;
124                    
125                    html = topRows.map(row => {
126                        const price = Number(row.price || row.closePrice || 0).toLocaleString('el-GR', {maximumFractionDigits: 2});
127                        const deltaPValue = parseFloat(row.pricePrevClosePricePDelta || 0);
128                        const deltaValue = parseFloat(row.pricePrevClosePriceDelta || 0);
129                        const delta = Number(deltaValue).toLocaleString('el-GR', {maximumFractionDigits: 2});
130                        const deltaP = Number(deltaPValue).toLocaleString('el-GR', {maximumFractionDigits: 2});
131                        const isUp = deltaPValue >= 0;
132                        const deltaClass = isUp ? 'fh-quote__delta--up' : 'fh-quote__delta--down';
133                        const sign = isUp ? '+' : '';
134
135                        return `
136                            <div class="fh-quote">
137                                <a href="/quote/${row.instrSysName}" class="fh-quote__symbol">${row.instrCode}</a>
138                                <div class="fh-quote__price">${price}</div>
139                                <div class="fh-quote__delta ${deltaClass}">${sign}${delta}</div>
140                                <div class="fh-quote__delta ${deltaClass}">${sign}${deltaP}%</div>
141                            </div>`;
142                    }).join('');
143                }
144
145                block.innerHTML = `<div class="fh-quotes__grid">${headerHtml}${html}</div>`;
146            });
147        })
148        .catch(() => {
149            quoteBlocks.forEach(block => {
150                block.innerHTML = `<div class="fh-quotes__error">Σφάλμα φόρτωσης δεδομένων.</div>`;
151            });
152        });
153});
154
155var tickerContent = [];
156tickerContent['ticker-metoxes'] = '';
157
158HTMLElement.prototype.marquee = function (args = {count: -1, speed: 17, leftToRight: false}) {
159    const element = this;
160    element.classList.add('marquee-started');
161
162    const textWidth = element.scrollWidth;
163    let offset = 0;
164    let width = offset;
165    const css = {
166        transform: element.style.transform,
167        overflow: element.style.overflow,
168        whiteSpace: element.style.whiteSpace,
169    };
170    const marqueeCss = {
171        transform: `translate(${width}px)`,
172        overflow: 'hidden',
173        whiteSpace: 'nowrap',
174    };
175    let i = 0;
176    let stop = textWidth * -1;
177    let isRunning = true;
178
179    // Apply marquee styling to start
180    Object.assign(element.style, marqueeCss);
181
182    // The main animation function
183    function go() {
184        // Stop condition based on max-height
185        if (getComputedStyle(element).maxHeight === '999998px') {
186            console.log('STOPPED DUE TO SEARCH');
187            Object.assign(element.style, css); // Restore original styles
188            isRunning = false;
189            return;
190        }
191
192        // Check if element exists; stop if it doesn’t
193        if (!document.body.contains(element)) {
194            isRunning = false;
195            return;
196        }
197
198        // Reset width for continuous scrolling
199        if (width === stop) {
200            i++;
201            if (i === args.count) {
202                Object.assign(element.style, css); // Restore original styles
203                isRunning = false;
204                return;
205            }
206            width = args.leftToRight ? -textWidth : offset;
207        }
208
209        // Update position
210        element.style.transform = `translate(${width}px)`;
211
212        // Increment or decrement width based on scroll direction
213        if (getComputedStyle(element).maxHeight !== '999999px') {
214            width += args.leftToRight ? 1 : -1;
215        }
216
217        if (isRunning) {
218            setTimeout(go, args.speed);
219        }
220    }
221
222    // Initialize width and stop positions based on direction
223    if (args.leftToRight) {
224        width = -textWidth + 1;
225        stop = offset;
226    } else {
227        width -= 1;
228    }
229
230    // Start animation
231    go();
232};
233
234function nxFormatPrice(x) {
235    return x.toString().replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '.');
236}
237
238function nxRoundTo(n, digits) {
239    if (digits === undefined) {
240        digits = 0;
241    }
242
243    var multiplicator = Math.pow(10, digits);
244    n = parseFloat((n * multiplicator).toFixed(11));
245    return Math.round(n) / multiplicator;
246}
247
248function nxJumpToTickerResult(el) {
249    let actTicker = document.querySelector('.output-wrapper.active');
250    actTicker.style.maxHeight = '999998px';
251    if (actTicker.classList.contains('marquee-started')) {
252        actTicker.classList.remove('marquee-started');
253        actTicker.classList.add('search-performed');
254    }
255    setTimeout(function () {
256        actTicker.style.transform = 'translate(' + (parseFloat(el.offsetLeft - 10) * -1) + 'px)';
257    }, 100);
258
259    if (!el.classList.contains('nx-symbol-found')) {
260        let cel = el.querySelector('span');
261        cel.classList.add('nx-symbol-found');
262        setTimeout(function () {
263            cel.classList.remove('nx-symbol-found');
264        }, 2500);
265    }
266}
267
268function nxNotFoundTickerResult() {
269    let el = document.querySelector('#search-ticker');
270    if (!el.classList.contains('nx-symbol-not-found')) {
271        let cel = el.querySelector('span');
272        cel.classList.add('nx-symbol-not-found');
273        cel.textContent = 'ΔΕΝ ΒΡΕΘΗΚΕ';
274        document.querySelector('#search-ticker-input').disabled = true;
275        cel.disabled = true;
276        setTimeout(function () {
277            cel.classList.remove('nx-symbol-not-found');
278            cel.textContent = 'ΑΝΑΖΗΤΗΣΗ';
279            cel.disabled = false;
280            document.querySelector('#search-ticker-input').disabled = false;
281            document.querySelector('#search-ticker-input').value = '';
282            document.querySelector('#search-ticker-input').focus();
283        }, 1500);
284    }
285}
286
287function nxTickerSearch(searchStr) {
288    var BreakException = {};
289    var nxTickerSearchFound = false;
290    if (searchStr) {
291        let upperSearchStr = searchStr.toUpperCase();
292        try {
293            [].forEach.call(
294                document.querySelectorAll('.output-wrapper.active span'),
295                function (el) {
296                    let tC = el.textContent.trim().toUpperCase();
297                    console.log('SEARCHING FOR ' + upperSearchStr);
298                    let firstResult = tC.lastIndexOf(upperSearchStr, 0) === 0;
299                    if (firstResult) {
300                        // TRY BEGINS WITH
301                        nxJumpToTickerResult(el);
302                        nxTickerSearchFound = true;
303                        throw BreakException;
304                    } else {
305                        // TRY CONTAINED
306                        if (tC.indexOf(upperSearchStr) !== -1) {
307                            nxJumpToTickerResult(el);
308                            nxTickerSearchFound = true;
309                            throw BreakException;
310                        }
311                    }
312                },
313            );
314        } catch (e) {
315            if (e !== BreakException) throw e;
316        }
317        if (!nxTickerSearchFound) {
318            nxNotFoundTickerResult();
319        }
320    }
321
322}
323
324////////////////
325// TICKERS START
326if (typeof nx_handleTickerData !== 'function') {
327    function nx_handleTickerData(IBData, tickerName, elementIDs) {
328
329        let itemName, itemCurrPrice, itemCurrChange, itemCurrChangeP, itemSysName, itemCatSysName;
330        let nxObj = IBData;
331
332        let addPlus = false;
333        let currPrice, currChange, txt;
334        tickerContent[tickerName] = '';
335
336        if (typeof nxObj !== 'undefined' && nxObj.hasOwnProperty('inbroker-transactions') &&
337            nxObj['inbroker-transactions'].hasOwnProperty('row')) { // FAIL-SAFE CHECK
338
339            let IBObj = nxObj['inbroker-transactions']['row'];
340
341            if (IBObj.id) {
342                console.log('mpika: ', IBObj);
343                itemName = IBObj.instrCode;
344                itemSysName = IBObj.instrSysName;
345                itemCatSysName = IBObj.categorySysName;
346                itemCurrPrice = (IBObj.closePrice > 0 ?
347                    IBObj.closePrice :
348                    (IBObj.price > 0 ? IBObj.price : IBObj.prevClosePrice));
349                itemCurrChange = (IBObj.closePrice > 0 ?
350                    IBObj.closePrevCloseDelta :
351                    (IBObj.price > 0 ? IBObj.pricePrevClosePriceDelta : 0));
352                itemCurrChangeP = (IBObj.closePrice > 0 ?
353                    IBObj.closePrevClosePDelta :
354                    (IBObj.price > 0 ? IBObj.pricePrevClosePricePDelta : 0));
355
356                // CHANGE FOR LIVE:
357                txt = (parseFloat(itemCurrChange) > 0 ?
358                    'arrow-up' :
359                    (parseFloat(itemCurrChange) < 0 ? 'arrow-down' : 'no-arrow'));
360                if (tickerName !== 'ticker-omologa' ||
361                    (tickerName === 'ticker-omologa' && itemCatSysName.substring(0, 10) === 'CORPORATE.')) {
362                    tickerContent[tickerName] += `
363                    <span class="ticker-item">
364                        <a href="/quote/${itemSysName}/">
365                            <span><strong>${itemName}</strong></span>
366                            <span class="${txt} ${txt}bg">${itemCurrPrice}</span>
367                            <span class="${txt}bg">${nxRoundTo(itemCurrChangeP, 2)}%</span>
368                        </a>
369                    </span>
370                    `;
371                }
372            } else {
373                let rowObj = {};
374                for (let i = 0; i < IBObj.length; i++) {
375                    rowObj = IBObj[i];
376
377                    itemName = rowObj.instrCode;
378                    itemSysName = rowObj.instrSysName;
379                    itemCatSysName = rowObj.categorySysName;
380
381                    itemCurrPrice = (rowObj.closePrice > 0 ?
382                        rowObj.closePrice :
383                        (rowObj.price > 0 ? rowObj.price : rowObj.prevClosePrice));
384
385                    itemCurrChange = (rowObj.closePrice > 0 ?
386                        rowObj.closePrevCloseDelta :
387                        (rowObj.price > 0 ? rowObj.pricePrevClosePriceDelta : 0));
388
389                    itemCurrChangeP = (rowObj.closePrice > 0 ?
390                        rowObj.closePrevClosePDelta :
391                        (rowObj.price > 0 ? rowObj.pricePrevClosePricePDelta : 0));
392
393                    // CHANGE FOR LIVE:
394                    txt = (parseFloat(itemCurrChange) > 0 ?
395                        'arrow-up' :
396                        (parseFloat(itemCurrChange) < 0 ? 'arrow-down' : 'no-arrow'));
397
398                    tickerContent[tickerName] += `
399                    <span class="ticker-item">
400                        <a href="/quote/${itemSysName}/">
401                            <span><strong>${itemName}</strong></span>
402                            <span class="${txt} ${txt}bg">${itemCurrPrice}</span>
403                            <span class="${txt}bg">${nxRoundTo(itemCurrChangeP, 2)}%</span>
404                        </a>
405                    </span>
406                    `;
407                }
408            }
409            nxConstuctTicker(tickerName);
410        }
411    }
412}
413
414function nxConstuctTicker(tickerName) {
415    let currTickerClass = tickerName + '-output',
416        currTicker = document.querySelector('.' + currTickerClass),
417        tmpTickerClass, tmpTicker, nxSkip, loopTicker, tmpVar,
418        nxTickers = ['ticker-metoxes'];
419
420    for (let i = 0; i < nxTickers.length; i++) {
421        loopTicker = nxTickers[i] + '-output';
422
423        if (tickerName === nxTickers[i]) {
424            if (!currTicker.classList.contains('active')) {
425                currTicker.classList.add('active');
426            }
427            if (!currTicker.classList.contains('is-init')) {
428                currTicker.setAttribute('data-speed', '0.45');
429                currTicker.setAttribute('data-pausable', 'true');
430                currTicker.innerHTML = `<div>${tickerContent[tickerName]}</div>`;
431            }
432            let tmpVar = document.querySelector('.' + currTickerClass);
433            if (!tmpVar.classList.contains('marquee-started') && !tmpVar.classList.contains('search-performed')) {
434                tmpVar.marquee();
435            } else {
436                if (tmpVar.classList.contains('marquee-started')) {
437                    console.log('TICKER ' + tickerName + ' NOT STARTED ALREADY RUNNING');
438                }
439                if (tmpVar.classList.contains('search-performed')) {
440                    console.log('TICKER ' + tickerName + ' NOT STARTED BLOCKED BY SEARCH');
441                }
442            }
443        } else {
444            tmpTickerClass = nxTickers[i] + '-output';
445            console.log(tmpTickerClass);
446            tmpTicker = document.querySelector('.' + tmpTickerClass);
447            if (tmpTicker.classList.contains('active')) {
448                tmpTicker.classList.remove('active');
449            }
450        }
451    }
452}
453
454let nxTickerMap = [];
455nxTickerMap['ticker-metoxes'] = 'EQ';
456
457fetch(FinanceHelperData.apiUrl)
458    .then(res => res.json())
459    .then(data => {
460        console.log(data);
461        nx_handleTickerData(data, 'ticker-metoxes')
462    })
463    .catch((err) => {
464        console.error("Finance Helper API fetch error:", err);
465    });
466
467// Load World Markets Stocks Ticker
468function loadWorldMarketsTicker() {
469    fetch('/feeds/indices.html')
470        .then(response => {
471            if (!response.ok) {
472                throw new Error('Network response was not ok');
473            }
474            return response.text();
475        })
476        .then(html => {
477            const stocksContainer = document.querySelector('.nav__stocks.container');
478            if (stocksContainer) {
479                stocksContainer.innerHTML = html;
480            }
481        })
482        .catch(error => {
483            console.error('Error loading world markets ticker:', error);
484        });
485}
486
487// Load on page load
488if (document.readyState === 'loading') {
489    document.addEventListener('DOMContentLoaded', loadWorldMarketsTicker);
490} else {
491    loadWorldMarketsTicker();
492}
493
494// Optionally reload every 5 minutes (300000 ms)
495setInterval(loadWorldMarketsTicker, 300000);

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.