|
26 | 26 | initPopupResize(); |
27 | 27 | initFileNavTooltips(); |
28 | 28 | initFileNavKeys(); |
| 29 | + initFunctionListPersistence(); |
29 | 30 |
|
30 | 31 | // Reveal page now that all init is done |
31 | 32 | document.documentElement.classList.remove('no-transitions'); |
|
1156 | 1157 | // =========================================== |
1157 | 1158 |
|
1158 | 1159 | function initSorting() { |
1159 | | - const headers = document.querySelectorAll('.file-list-header .sortable, .functions-header .sortable'); |
| 1160 | + var headerSets = [ |
| 1161 | + { |
| 1162 | + selector: '.file-list-header .sortable, .functions-header .sortable', |
| 1163 | + getContainer: function() { |
| 1164 | + return document.getElementById('file-list') || document.querySelector('.functions-body'); |
| 1165 | + }, |
| 1166 | + defaultSort: { key: 'filename', ascending: true } |
| 1167 | + }, |
| 1168 | + { |
| 1169 | + selector: '.source-function-header .sortable', |
| 1170 | + getContainer: function() { |
| 1171 | + return document.querySelector('.source-functions-list'); |
| 1172 | + }, |
| 1173 | + defaultSort: null |
| 1174 | + } |
| 1175 | + ]; |
1160 | 1176 |
|
1161 | | - headers.forEach(function(header) { |
1162 | | - header.addEventListener('click', function() { |
1163 | | - const sortKey = this.dataset.sort; |
1164 | | - const isAscending = this.classList.contains('sorted-ascending'); |
| 1177 | + headerSets.forEach(function(set) { |
| 1178 | + var headers = document.querySelectorAll(set.selector); |
| 1179 | + if (!headers.length) return; |
1165 | 1180 |
|
1166 | | - // Remove sorted class from all headers |
1167 | | - headers.forEach(function(h) { |
1168 | | - h.classList.remove('sorted-ascending', 'sorted-descending'); |
1169 | | - }); |
| 1181 | + headers.forEach(function(header) { |
| 1182 | + header.addEventListener('click', function() { |
| 1183 | + var sortKey = this.dataset.sort; |
| 1184 | + var isAscending = this.classList.contains('sorted-ascending'); |
1170 | 1185 |
|
1171 | | - // Toggle sort direction |
1172 | | - this.classList.add(isAscending ? 'sorted-descending' : 'sorted-ascending'); |
| 1186 | + headers.forEach(function(h) { |
| 1187 | + h.classList.remove('sorted-ascending', 'sorted-descending'); |
| 1188 | + }); |
| 1189 | + |
| 1190 | + this.classList.add(isAscending ? 'sorted-descending' : 'sorted-ascending'); |
1173 | 1191 |
|
1174 | | - // Sort the list |
1175 | | - sortList(sortKey, !isAscending); |
| 1192 | + sortList(set.getContainer(), sortKey, !isAscending); |
| 1193 | + }); |
1176 | 1194 | }); |
1177 | | - }); |
1178 | 1195 |
|
1179 | | - // Initial sort: directories first, then by filename |
1180 | | - sortList('filename', true); |
| 1196 | + if (set.defaultSort) { |
| 1197 | + sortList(set.getContainer(), set.defaultSort.key, set.defaultSort.ascending); |
| 1198 | + } |
| 1199 | + }); |
1181 | 1200 | } |
1182 | 1201 |
|
1183 | | - function sortList(key, ascending) { |
1184 | | - const container = document.getElementById('file-list') || document.querySelector('.functions-body'); |
| 1202 | + function sortList(container, key, ascending) { |
1185 | 1203 | if (!container) return; |
1186 | 1204 | // Virtual scroll handles its own sorting |
1187 | 1205 | if (container.dataset.virtualScroll) return; |
1188 | 1206 |
|
1189 | | - const rows = Array.from(container.children); |
| 1207 | + var headerEl = container.querySelector('.source-function-header, .file-list-header, .functions-header'); |
| 1208 | + var rows = Array.from(container.children).filter(function(el) { return el !== headerEl; }); |
1190 | 1209 |
|
1191 | 1210 | rows.sort(function(a, b) { |
1192 | 1211 | // Directories always come first |
1193 | | - const aIsDir = a.classList.contains('directory'); |
1194 | | - const bIsDir = b.classList.contains('directory'); |
| 1212 | + var aIsDir = a.classList.contains('directory'); |
| 1213 | + var bIsDir = b.classList.contains('directory'); |
1195 | 1214 | if (aIsDir && !bIsDir) return -1; |
1196 | 1215 | if (!aIsDir && bIsDir) return 1; |
1197 | 1216 |
|
1198 | | - let aVal = a.dataset[key] || a.querySelector('[data-sort]')?.dataset.sort || ''; |
1199 | | - let bVal = b.dataset[key] || b.querySelector('[data-sort]')?.dataset.sort || ''; |
| 1217 | + var aVal = a.dataset[key] || a.querySelector('[data-sort]')?.dataset.sort || ''; |
| 1218 | + var bVal = b.dataset[key] || b.querySelector('[data-sort]')?.dataset.sort || ''; |
1200 | 1219 |
|
1201 | 1220 | // Try to parse as numbers |
1202 | | - const aNum = parseFloat(aVal); |
1203 | | - const bNum = parseFloat(bVal); |
| 1221 | + var aNum = parseFloat(aVal); |
| 1222 | + var bNum = parseFloat(bVal); |
1204 | 1223 |
|
1205 | 1224 | if (!isNaN(aNum) && !isNaN(bNum)) { |
1206 | 1225 | return ascending ? aNum - bNum : bNum - aNum; |
|
1633 | 1652 | localStorage.setItem('gcovr-view-mode', 'nested'); |
1634 | 1653 |
|
1635 | 1654 | // Re-run sorting to maintain state |
1636 | | - sortList('filename', true); |
| 1655 | + sortList(document.getElementById('file-list') || document.querySelector('.functions-body'), 'filename', true); |
1637 | 1656 | } |
1638 | 1657 |
|
1639 | 1658 | buttons.forEach(function(btn) { |
|
1922 | 1941 | if (scrollBox && row) { |
1923 | 1942 | var thead = scrollBox.querySelector('thead'); |
1924 | 1943 | var theadHeight = thead ? thead.offsetHeight : 0; |
1925 | | - scrollBox.scrollTo({ top: row.offsetTop - theadHeight - 8, behavior: 'smooth' }); |
| 1944 | + scrollBox.scrollTo({ top: row.offsetTop - theadHeight - 8, behavior: 'instant' }); |
1926 | 1945 | } |
1927 | 1946 | history.replaceState(null, '', this.getAttribute('href')); |
1928 | 1947 | // Highlight the target row (clear any previous highlight first) |
|
1940 | 1959 | // =========================================== |
1941 | 1960 |
|
1942 | 1961 | function initLineHighlight() { |
| 1962 | + var clickedFnItem = null; |
| 1963 | + |
1943 | 1964 | function highlightFromHash(scroll) { |
1944 | 1965 | var prev = document.querySelector('.highlight-target'); |
1945 | 1966 | if (prev) prev.classList.remove('highlight-target'); |
| 1967 | + var prevFn = document.querySelector('.source-function-item.selected'); |
| 1968 | + if (prevFn) prevFn.classList.remove('selected'); |
1946 | 1969 | var id = window.location.hash.slice(1); |
1947 | 1970 | if (!id) return; |
1948 | 1971 | var el = document.getElementById(id); |
1949 | 1972 | if (!el) return; |
| 1973 | + var fnItem = clickedFnItem || document.querySelector('.source-function-item[href="#' + id + '"]'); |
| 1974 | + clickedFnItem = null; |
| 1975 | + if (fnItem) fnItem.classList.add('selected'); |
1950 | 1976 | var row = el.closest('tr'); |
1951 | 1977 | if (row) { |
1952 | 1978 | row.classList.add('highlight-target'); |
|
1955 | 1981 | if (scrollBox) { |
1956 | 1982 | var thead = scrollBox.querySelector('thead'); |
1957 | 1983 | var theadHeight = thead ? thead.offsetHeight : 0; |
1958 | | - scrollBox.scrollTo({ top: row.offsetTop - theadHeight - 8, behavior: 'smooth' }); |
| 1984 | + scrollBox.scrollTo({ top: row.offsetTop - theadHeight - 8, behavior: 'instant' }); |
1959 | 1985 | } else { |
1960 | 1986 | row.scrollIntoView({ block: 'center' }); |
1961 | 1987 | } |
1962 | 1988 | } |
1963 | 1989 | } |
1964 | 1990 | } |
1965 | 1991 |
|
| 1992 | + // Handle clicks on function list items directly |
| 1993 | + var fnList = document.querySelector('.source-functions-list'); |
| 1994 | + if (fnList) { |
| 1995 | + fnList.addEventListener('click', function(e) { |
| 1996 | + var item = e.target.closest('.source-function-item'); |
| 1997 | + if (!item) return; |
| 1998 | + e.preventDefault(); |
| 1999 | + clickedFnItem = item; |
| 2000 | + var href = item.getAttribute('href'); |
| 2001 | + if (href) history.replaceState(null, '', href); |
| 2002 | + highlightFromHash(true); |
| 2003 | + }); |
| 2004 | + } |
| 2005 | + |
1966 | 2006 | // Event delegation: single listener on the table container |
1967 | 2007 | var container = document.querySelector('.source-table-container'); |
1968 | 2008 | if (container) { |
|
2119 | 2159 | }); |
2120 | 2160 | } |
2121 | 2161 |
|
| 2162 | + function initFunctionListPersistence() { |
| 2163 | + var details = document.querySelector('details.source-functions'); |
| 2164 | + if (!details) return; |
| 2165 | + |
| 2166 | + var key = 'gcovr-fn-list-open'; |
| 2167 | + if (sessionStorage.getItem(key) === 'true') { |
| 2168 | + details.setAttribute('open', ''); |
| 2169 | + } |
| 2170 | + |
| 2171 | + details.addEventListener('toggle', function() { |
| 2172 | + sessionStorage.setItem(key, details.open ? 'true' : 'false'); |
| 2173 | + }); |
| 2174 | + } |
| 2175 | + |
2122 | 2176 | })(); |
0 commit comments