PageSourceSearch

https://www.finance-magazin.de/wp-content/plugins/px-multiples-das…/js/components/main-table-view.js?v=1.0.10

js finance-magazin.de collected 2026-10-02 06:43:21 UTC 24,151 bytes, 491 lines download raw bytes

1import {dataStorage} from './dataStorage.js?v=1.0.10';
2import {exportFunctions} from './exportFunctions.js?v=1.0.10';
3import axios from '../vendor/axios.min.js';
4
5export default {
6    data() {
7        return {
8            tableId: 'px-multiples-dashboard--table-datatable',
9            tableHeaderOffset: 0,
10            dataStorage
11        }
12    },
13    // inject: ['EventBus'],
14    mounted() {
15    },
16    // created() {
17    //     this.EventBus.on('applyTableFilters', this.applyTableFilters);
18    // },
19    // beforeUnmount() {
20    //     this.EventBus.off('applyTableFilters', this.applyTableFilters);
21    // },
22    computed: {
23        // computed getters are cached based on their reactive dependencies
24        hasTableFilters() {
25            const tableFiltersDiffer = !this.dataStorage.compareCleanedObjects(
26                this.dataStorage.activeTableFilters,
27                this.dataStorage.getEmptyTableFilters(),
28                ['tableIsLoading']
29            );
30            return this.dataStorage.activeTableFilters && Object.keys(this.dataStorage.activeTableFilters).length > 0 && tableFiltersDiffer;
31        },
32        hasCompareFilter() {
33            if (this.dataStorage.activeTableFilters && Object.keys(this.dataStorage.activeTableFilters).length > 0) {
34                if (this.dataStorage.activeTableFilters.datum[0] === 'compare' || this.dataStorage.activeTableFilters.datum[0] === 'custom-period-compare') {
35                    return true;
36                }
37            }
38            return false;
39        },
40        getCompareFilterType() {
41            if (this.dataStorage.activeTableFilters && Object.keys(this.dataStorage.activeTableFilters).length > 0) {
42                if (this.dataStorage.activeTableFilters.datum[0] === 'compare' || this.dataStorage.activeTableFilters.datum[0] === 'custom-period-compare') {
43                    if (this.dataStorage.activeTableFilters?.compareType === 'total') {
44                        return 'Total';
45                    } else {
46                        return '%';
47                    }
48                }
49            }
50            return '';
51        }
52    },
53    methods: {
54        buildTable(data) {
55            if (!data || !data.length) {
56                console.error('MainTableView: No data provided');
57                dataStorage.resetTableFilters();
58
59                toastr.error('Es gab einen Fehler beim Laden der Daten. Filter wurden zurückgesetzt.');
60                return;
61            }
62
63            const $tableSupportLinks = jQuery('#px-multiples-dashboard--support-links-table');
64
65            if (jQuery?.fn?.dataTable?.isDataTable('#' + this.tableId)) {
66                // update existing table
67
68                this.dataStorage.tableObject = jQuery('#' + this.tableId).DataTable();
69
70                this.dataStorage.tableObject.columns(['ebitdamin:name', 'ebitdamax:name']).visible(
71                    !dataStorage.activeTableFilters?.kennzahlen?.length || dataStorage.activeTableFilters.kennzahlen.includes('ebitda')
72                );
73                this.dataStorage.tableObject.columns(['ebitminimum:name', 'ebitmaximum:name']).visible(
74                    !dataStorage.activeTableFilters?.kennzahlen?.length || dataStorage.activeTableFilters.kennzahlen.includes('ebit')
75                );
76                this.dataStorage.tableObject.columns(['umsatzminimum:name', 'umsatzmaximum:name']).visible(
77                    !dataStorage.activeTableFilters?.kennzahlen?.length || dataStorage.activeTableFilters.kennzahlen.includes('umsatz')
78                );
79
80                // clear existing and add new data
81                this.dataStorage.tableObject.clear();
82                this.dataStorage.tableObject.rows.add(data);
83
84                // redraw the table
85                this.dataStorage.tableObject.draw();
86
87            } else {
88                // create new table
89
90                let columnConfig = [
91                    {
92                        name: 'id',
93                        data: 'wdt_ID'
94                    },
95                    {
96                        name: 'branche',
97                        data: 'branche'
98                    },
99                    {
100                        name: 'sortdate',
101                        data: null,
102                        render: {
103                            // default, for display and export
104                            '_': function(data, type, row) {
105                                return row.monat + ' ' + row.jahr;
106                            },
107                            // for sorting
108                            'sort': 'sortdate',
109                        }
110                    },
111                    {
112                        name: 'unternehmensgrsse',
113                        data: null,
114                        className: 'unternehmensgrsse-cell',
115                        render: {
116                            // default, for display and export
117                            '_': function(data, type, row) {
118                                if (!row || !row.unternehmensgrsse) {
119                                    return '<span class="empty-unternehmensgrsse" data-tooltip-content="Keine Daten verfügbar">-</span>';
120                                }
121                                if (row.unternehmensgrsse === 'Micro-Cap') {
122                                    return `<span class="${row.unternehmensgrsse.toLowerCase()}" data-tooltip-content="Micro-Cap seit September 2022 verfügbar">${row.unternehmensgrsse}</span>`;
123                                }
124                                return `<span class="${row.unternehmensgrsse.toLowerCase()}">${row.unternehmensgrsse}</span>`;
125                            },
126                            // for sorting
127                            'sort': 'unternehmensgrssesort',
128                        }
129                    },
130                ];
131                let numberColumnNames = ['ebitminimum', 'ebitmaximum', 'ebitdamin', 'ebitdamax', 'umsatzminimum', 'umsatzmaximum'];
132
133                numberColumnNames.forEach(name => {
134                    let baseName = name.replace(/minimum|maximum|min|max/g, '');
135
136                    columnConfig.push({
137                        name: name,
138                        data: name,
139                        className: 'dt-type-numeric',
140                        render: {
141                            // default, for display
142                            '_': function(data, type, row) {
143                                let output = row[name];
144                                if (row.comparisonData?.[name]) {
145                                    let comparisonData = dataStorage.formatComparisonData(row, name);
146                                    if (comparisonData) {
147                                        output = comparisonData;
148                                    }
149                                }
150                                output = dataStorage.formatTableNumberData(output);
151                                if (output === '-') {
152                                    output = '<span class="empty-number" data-tooltip-content="Keine Daten verfügbar">-</span>';
153                                }
154                                return output;
155                            },
156                            // special export, without comparison data
157                            exportCsv: function(data, type, row) {
158                                return dataStorage.formatTableNumberData(row[name]);
159                            },
160                            // special export, without comparison data and with "."
161                            exportExcel: function(data, type, row) {
162                                return dataStorage.formatTableExcelData(row[name]);
163                            },
164                            // for sorting
165                            'sort': name,
166                        },
167                        visible: !dataStorage.activeTableFilters?.kennzahlen.length || dataStorage.activeTableFilters?.kennzahlen?.includes(baseName)
168                    });
169                });
170
171                let $tableElement = jQuery('#' + this.tableId);
172                if ($tableElement.length === 1) {
173
174                    this.calculateHeaderOffset();
175
176                    const $headerWrap = jQuery('.td-header-template-wrap');
177
178                    if ($headerWrap.length) {
179                        // if the header is resized, recalculate the offset
180                        const observer = new ResizeObserver(this.calculateHeaderOffset);
181                        observer.observe($headerWrap.get(0));
182                    }
183
184                    // recalc on scroll, because parts of header get fixed
185                    jQuery(window).on('scroll', window['throttle'](this.calculateHeaderOffset.bind(this), 100));
186
187                    this.dataStorage.tableObject = $tableElement.DataTable({
188                        processing: true,
189                        data: data,
190                        columns: columnConfig,
191                        order: [
192                            [2, 'desc'], // first sort by date
193                            [1, 'asc'], // then by branche
194                            [3, 'asc'] // then by unternehmensgrsse
195                        ],
196                        fixedHeader: {
197                            headerOffset: (this.tableHeaderOffset)
198                        },
199                        layout: {
200                            topStart: null,
201                            topEnd: null,
202                            bottomStart: $tableSupportLinks.length ? $tableSupportLinks : null,
203                            bottomEnd: ['pageLength', 'info', 'paging'],
204                        },
205                        stripeClasses: ['odd', 'even'],
206                        scrollX: (window.innerWidth < 1200), // allow horizontal scrolling on smaller screens
207                        buttons: [
208                            {
209                                extend: 'csv',
210                                name: 'csvExport',
211                                filename: dataStorage.formatDownloadFilename,
212                                title: 'FINANCE Multiples',
213                                exportOptions: {
214                                    columns: ':visible',
215                                    orthogonal: 'exportCsv',
216                                    format: {
217                                        header: dataStorage.formatExportHeader
218                                    }
219                                }
220                            },
221                            {
222                                extend: 'excel',
223                                name: 'excelExport',
224                                filename: dataStorage.formatDownloadFilename,
225                                sheetName: 'Multiples',
226                                title: 'FINANCE Multiples',
227                                exportOptions: {
228                                    columns: ':visible',
229                                    orthogonal: 'exportExcel',
230                                    format: {
231                                        header: dataStorage.formatExportHeader
232                                    }
233                                },
234                                autoFilter: true,
235
236                                // customize the excel file
237                                customize: exportFunctions.customizeExcel,
238                            }
239                        ],
240                        language: {
241                            decimal: ',',
242                            lengthMenu: "Zeilen pro Seite: _MENU_",
243                            paginate: {
244                                previous: '<i class="fas fa-chevron-left"></i>',
245                                next: '<i class="fas fa-chevron-right"></i>'
246                            },
247                            aria: {
248                                paginate: {
249                                    previous: 'Zurück',
250                                    next: 'Weiter'
251                                }
252                            },
253                            url: $tableElement.data('languagejson') ?? ''
254                        },
255                        lengthMenu: [10, 50, 100, 200],
256                        pageLength: 100,
257                        pagingType: 'simple_numbers',
258                        searching: false,
259                        drawCallback: function(settings) {
260                            // get table container width and save to dataStorage
261                            const container = this.api()?.table()?.container();
262                            if (container) {
263                                const tableWidth = container.offsetWidth;
264                                if (tableWidth > 0) {
265                                    dataStorage.tableWidth = tableWidth;
266                                }
267
268                                // show pagination only if more records than current pageLength
269                                const pageLength = this.api().page.len();
270                                const totalRecords = this.api().data().length;
271                                if (totalRecords <= pageLength) {
272                                    jQuery(container).find('.dt-paging').hide();
273                                } else {
274                                    jQuery(container).find('.dt-paging').show();
275
276                                    // add tooltips after 500ms to finish rendering
277                                    setTimeout(function() {
278                                        const $nextButtons = jQuery(container).find('.dt-paging-button.next');
279                                        if ($nextButtons.length > 0) {
280                                            tippy(
281                                                $nextButtons.toArray(),
282                                                {
283                                                    content: 'Weiter',
284                                                    touch: 'hold',
285                                                }
286                                            );
287                                        }
288                                        const $prevButtons = jQuery(container).find('.dt-paging-button.previous');
289                                        if ($prevButtons.length > 0) {
290                                            tippy(
291                                                $prevButtons.toArray(),
292                                                {
293                                                    content: 'Zurück',
294                                                    touch: 'hold',
295                                                }
296                                            );
297                                        }
298                                    }, 500);
299                                }
300
301                                setTimeout(function() {
302                                    const $length = jQuery(container).find('.dt-length');
303                                    if ($length.length > 0) {
304                                        tippy(
305                                            $length.toArray(),
306                                            {
307                                                content: 'Anzahl angezeigter Zeilen',
308                                                touch: 'hold',
309                                            }
310                                        );
311                                    }
312
313                                    // init tooltips in table
314                                    const $tooltipElements = jQuery(container).find('[data-tooltip-content]');
315                                    if ($tooltipElements.length > 0) {
316                                        tippy(
317                                            $tooltipElements.toArray(),
318                                            {
319                                                allowHTML: true,
320                                                content: (reference) => reference.getAttribute('data-tooltip-content'),
321                                                touch: 'hold',
322                                            }
323                                        );
324                                    }
325
326                                }, 500);
327
328                                const api = this.api();
329                                const order = api.order();
330                                const rows = api.rows({page: 'current'}).nodes();
331
332                                // get columns to group by from current order
333                                let groupCols = [];
334                                const orderCols = jQuery.map(order, function(o) {
335                                    return o[0];
336                                });
337                                // default is ordered by 3 columns: do not group by column-3 in this case
338                                if (orderCols.length > 2) {
339                                    // remove column-3 from grouping if it’s in there
340                                    groupCols = jQuery.grep(orderCols, function(idx) {
341                                        return idx !== 3;
342                                    });
343                                } else {
344                                    // if only one column is sorted, use it for grouping
345                                    groupCols = orderCols;
346                                }
347
348                                // clear old dividers
349                                jQuery(rows).removeClass('group-divider');
350
351                                // keep track of last seen values per grouping column
352                                let lastVals = {};
353
354                                // walk each rendered row in display order
355                                jQuery.each(rows, function(i, row) {
356                                    let isBreak = false;
357
358                                    // check each grouping column for a change
359                                    jQuery.each(groupCols, function(_, colIdx) {
360                                        const val = api.cell(row, colIdx, {page: 'current'}).render('sort');
361                                        if (lastVals[colIdx] !== undefined && val !== lastVals[colIdx]) {
362                                            isBreak = true;
363                                            return false;
364                                        }
365                                    });
366
367                                    // update lastVals
368                                    jQuery.each(groupCols, function(_, colIdx) {
369                                        lastVals[colIdx] = api.cell(row, colIdx, {page: 'current'}).render('sort');
370                                    });
371
372                                    if (isBreak) {
373                                        jQuery(row).addClass('group-divider');
374                                    }
375                                });
376                            }
377                        },
378
379                        // force odd/even classes for rows
380                        rowCallback: function(row, data, displayIndex) {
381                            if (displayIndex % 2 === 0) {
382                                // even index → “odd‐numbered” row in human terms
383                                jQuery(row)
384                                    .removeClass('even')   // clean up in case it was there from a previous draw
385                                    .addClass('odd');
386                            } else {
387                                // odd index → “even‐numbered” row
388                                jQuery(row)
389                                    .removeClass('odd')
390                                    .addClass('even');
391                            }
392                        }
393                    });
394                }
395            }
396        },
397        calculateHeaderOffset() {
398            const $headerWrap = jQuery('.td-header-template-wrap');
399            const $wpadminbar = jQuery('#wpadminbar');
400
401            this.tableHeaderOffset = 0;
402            if ($headerWrap.length === 1) {
403
404                // find all visible fixed descendants
405                const $fixedChildren = $headerWrap
406                    .find('*')
407                    .filter((_, el) =>
408                        jQuery(el).css('display') !== 'none' &&
409                        jQuery(el).css('position') === 'fixed'
410                    );
411
412                if ($fixedChildren.length) {
413                    // sum the heights of the fixed elements
414                    $fixedChildren.each((_, el) => {
415                        this.tableHeaderOffset += el.getBoundingClientRect().height;
416                    });
417                } else {
418                    // no fixed kids → take the wrapper's full rendered height
419                    this.tableHeaderOffset += parseInt($headerWrap[0].getBoundingClientRect().height);
420                    // this.tableHeaderOffset += parseInt($headerWrap.height());
421                }
422
423            }
424            if ($wpadminbar.length === 1 && $wpadminbar.css('position') === 'fixed') {
425                this.tableHeaderOffset += parseInt($wpadminbar.height());
426            }
427
428            if (this.dataStorage.tableObject !== null && this.dataStorage.tableObject.fixedHeader) {
429                this.dataStorage.tableObject.fixedHeader.headerOffset(this.tableHeaderOffset);
430            }
431        }
432    },
433    watch: {
434        // TODO: move to dataStorage?
435        'dataStorage.activeTableFilters': function(activeTableFilters, oldTableFilters) {
436            // run only on changes
437            if (dataStorage.compareCleanedObjects(activeTableFilters, oldTableFilters, ['tableIsLoading'])) {
438                dataStorage.markTableExportComplete();
439
440                // hide loading indicator, if active
441                if (dataStorage.activeTableFilters.tableIsLoading) {
442                    dataStorage.activeTableFilters.tableIsLoading = false;
443                }
444                return;
445            }
446
447            // check if filter_id is in the URL and is numeric
448            const urlParams = new URLSearchParams(window.location.search);
449            const filterId = urlParams.get('filter_id');
450            if (filterId && !isNaN(filterId)) {
451                const numericFilterId = parseInt(filterId);
452                if (
453                    // check only NULL, if empty string it means it was manually resetted
454                    dataStorage.activeCustomFilter === null ||
455                    (
456                        dataStorage.activeCustomFilter?.filter_id > 0 &&
457                        dataStorage.activeCustomFilter?.filter_id !== numericFilterId
458                    )
459                ) {
460                    // if filter_id is in URL but customFilter not yet loaded, skip
461                    dataStorage.exportConfig.exportRequested = false;
462                    return;
463                }
464            }
465
466            // show loading indicator
467            if (!dataStorage.activeTableFilters.tableIsLoading) {
468                dataStorage.activeTableFilters.tableIsLoading = true;
469            }
470
471            axios.post('/wp-json/px-multiples-dashboard/v1/multiples', {
472                filter: activeTableFilters,
473                singleReportConfig: dataStorage.singleReportConfig
474            }).then((response) => {
475                if (response && response.status === 200 && response.data) {
476                    this.buildTable(response.data);
477                    dataStorage.markTableExportComplete();
478                }
479            }).catch((error) => {
480                console.error('MainTableView: Multiples API error', error);
481                dataStorage.markTableExportComplete();
482            }).finally(() => {
483
484                // hide loading indicator
485                if (dataStorage.activeTableFilters.tableIsLoading) {
486                    dataStorage.activeTableFilters.tableIsLoading = false;
487                }
488            });
489        }
490    },
491}

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.