PageSourceSearch

https://freseniusmedicalcare.com/etc.clientlibs/fresenius-global-c…/content/text/v1/text/clientlibs.js

js freseniusmedicalcare.com collected 2026-10-02 08:32:14 UTC 8,096 bytes, 208 lines download raw bytes

1document.addEventListener("DOMContentLoaded", () => {
2  document.querySelectorAll('.cmp-text').forEach(container => {
3    const table = container.querySelector('table');
4    if (!table) return;
5
6    const tbodys = table.querySelectorAll('tbody');
7    let headerRow, dataRows = [];
8    if (tbodys.length === 1) {
9      const rows = Array.from(tbodys[0].querySelectorAll('tr'));
10      headerRow = rows[0];
11      dataRows = rows.slice(1);
12    } else if (tbodys.length > 1) {
13      headerRow = tbodys[0].querySelector('tr');
14      dataRows = Array.from(tbodys[1].querySelectorAll('tr'));
15    } else return;
16
17    const rowsPerPage = parseInt(container.querySelector('[data-max-items]')?.dataset.maxItems) || 5;
18    let currentRows = [...dataRows], currentPage = 1, sortColumnIndex = null, sortDirection = 'asc';
19
20    const headerCells = headerRow.querySelectorAll('th');
21    const enableSearch = container.querySelector('.cmp-text__table-search');
22    const enableSort = container.querySelector('.cmp-text__table-sort');
23    const enablePagination = container.querySelector('.cmp-text__table-pagination');
24    const noResultsMessage = container.querySelector(".cmp-text__table-no-results-message");
25
26    const getPageRows = () => enablePagination ? currentRows.slice((currentPage - 1) * rowsPerPage, currentPage * rowsPerPage) : currentRows;
27
28    const updateTableBody = () => {
29      const targetBody = tbodys.length === 1 ? tbodys[0] : tbodys[1];
30      targetBody.innerHTML = '';
31      if (tbodys.length === 1) targetBody.appendChild(headerRow);
32      getPageRows().forEach(row => targetBody.appendChild(row));
33    };
34
35    const resetSorting = () => {
36      sortColumnIndex = null;
37      sortDirection = 'asc';
38      currentPage = 1;
39      headerCells.forEach(th => th.classList.remove('th-sort-asc', 'th-sort-desc'));
40    };
41
42    const scrollToSearch = () => {
43      const searchContainer = container.querySelector('.cmp-text__table-search-container');
44      if (searchContainer) {
45        window.scrollTo({
46          top: window.pageYOffset + searchContainer.getBoundingClientRect().top - window.innerHeight * 0.3,
47          behavior: 'smooth'
48        });
49      }
50    };
51
52    const toggleNoResultsMessage = () => {
53      const hasResults = currentRows.length > 0;
54      noResultsMessage && (noResultsMessage.style.display = hasResults ? 'none' : 'block');
55      const paginationContainer = container.querySelector('.pagination');
56      const paginationLabel = container.querySelector('.cmp-text__table-pagination-lable');
57      const paginationButtons = paginationContainer?.querySelectorAll("button");
58
59      if (paginationContainer && paginationLabel) {
60        paginationContainer.style.display = paginationLabel.style.display = hasResults ? 'block' : 'none';
61        paginationButtons?.forEach(btn => btn.style.display = hasResults ? 'inline-block' : 'none');
62      }
63    };
64
65    if (enableSearch) {
66      const searchContainer = document.createElement('div');
67      searchContainer.className = 'cmp-text__table-search-container';
68      searchContainer.innerHTML = `<input type="text" id="filterInput" placeholder="Filter" /><span class="clear-button" style="display:none;">X</span>`;
69      container.insertBefore(searchContainer, table);
70
71      const filterInput = searchContainer.querySelector('#filterInput');
72      const clearButton = searchContainer.querySelector('.clear-button');
73
74      const filterRows = (rows, query) => !query ? rows : rows.filter(row => [...row.cells].some(cell => cell.textContent.toLowerCase().includes(query.toLowerCase())));
75
76      filterInput.addEventListener('input', () => {
77        clearButton.style.display = filterInput.value ? 'inline' : 'none';
78        currentRows = filterRows(dataRows, filterInput.value);
79        resetSorting();
80        renderTable();
81        toggleNoResultsMessage();
82      });
83
84      clearButton.addEventListener('click', () => {
85        filterInput.value = '';
86        clearButton.style.display = 'none';
87        currentRows = [...dataRows];
88        resetSorting();
89        renderTable();
90        toggleNoResultsMessage();
91      });
92    }
93
94    if (enableSort) {
95      headerCells.forEach((th, i) => {
96        th.classList.add('sortable');
97        th.addEventListener('click', () => {
98          sortDirection = (sortColumnIndex === i && sortDirection === 'asc') ? 'desc' : 'asc';
99          headerCells.forEach(th => th.classList.remove('th-sort-asc', 'th-sort-desc'));
100          th.classList.add(`th-sort-${sortDirection}`);
101          currentRows.sort((a, b) => {
102            const aText = a.cells[i].textContent.trim().toLowerCase();
103            const bText = b.cells[i].textContent.trim().toLowerCase();
104            return sortDirection === 'asc' ? aText.localeCompare(bText) : bText.localeCompare(aText);
105          });
106          sortColumnIndex = i;
107          currentPage = 1;
108          renderTable();
109        });
110      });
111    }
112
113    const updatePagination = (start, end, total) => {
114      container.querySelectorAll('.cmp-text__table-pagination-lable').forEach(label => {
115        if (!label.dataset.template) label.dataset.template = label.textContent || '';
116        label.textContent = label.dataset.template.replace(/#start/g, start).replace(/#end/g, end).replace(/#total/g, total);
117      });
118    };
119  const renderPagination = () => {
120  const totalPages = Math.ceil(currentRows.length / rowsPerPage);
121  if (totalPages <= 1) return;
122  let paginationDiv = container.querySelector('#pagination');
123  if (!paginationDiv) {
124    paginationDiv = Object.assign(document.createElement('div'), {
125      id: 'pagination',
126      className: 'pagination'
127    });
128    container.appendChild(paginationDiv);
129  }
130  paginationDiv.innerHTML = '';
131
132  const createButton = (label, disabled, onClick, classes = '') => {
133    const btn = document.createElement('button');
134    btn.textContent = label;
135    btn.disabled = disabled;
136    if (classes) btn.className = classes;
137    btn.addEventListener('click', onClick);
138    return btn;
139  };
140
141  const createEllipsis = (direction) => {
142    const span = document.createElement('span');
143    span.textContent = '...';
144    span.className = 'pagination-ellipsis';
145    span.addEventListener('click', () => {
146      const jump = 5;
147      currentPage = Math.max(1, Math.min(totalPages, currentPage + (direction === 'right' ? jump : -jump)));
148      renderTable();
149    });
150    return span;
151  };
152
153  paginationDiv.appendChild(createButton('‹', currentPage === 1, () => {
154    if (currentPage > 1) {
155      currentPage--;
156      renderTable();
157    }
158  }, currentPage === 1 ? 'prev-disable' : ''));
159
160  const pageButtons = [1];
161  let start = Math.max(2, currentPage - 1);
162  let end = Math.min(totalPages - 1, currentPage + 1);
163
164  if (currentPage <= 2) {
165    end = Math.min(3, totalPages - 1);
166  } else if (currentPage >= totalPages - 2) {
167    start = Math.max(2, totalPages - 3);
168  }
169
170  if (start > 2) pageButtons.push('left-ellipsis');
171  for (let i = start; i <= end; i++) pageButtons.push(i);
172  if (end < totalPages - 1) pageButtons.push('right-ellipsis');
173  if (totalPages > 1) pageButtons.push(totalPages);
174
175  pageButtons.forEach(item => {
176    if (item === 'left-ellipsis') {
177      paginationDiv.appendChild(createEllipsis('left'));
178    } else if (item === 'right-ellipsis') {
179      paginationDiv.appendChild(createEllipsis('right'));
180    } else {
181      const btn = createButton(item, item === currentPage, () => {
182        currentPage = item;
183        renderTable();
184      }, item === currentPage ? 'active' : '');
185      paginationDiv.appendChild(btn);
186    }
187  });
188
189  paginationDiv.appendChild(createButton('›', currentPage === totalPages, () => {
190    if (currentPage < totalPages) {
191      currentPage++;
192      renderTable();
193    }
194  }, currentPage === totalPages ? 'next-disable' : ''));
195};
196
197    const renderTable = () => {
198      updateTableBody();
199      if (enablePagination) {
200        renderPagination();
201        updatePagination((currentPage - 1) * rowsPerPage + 1, Math.min(currentPage * rowsPerPage, currentRows.length), currentRows.length);
202        scrollToSearch();
203      }
204    };
205
206    renderTable();
207  });
208});

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.