Skip to content

Commit 7bbaaf0

Browse files
committed
updating button to follow local clicks
1 parent d9cc40b commit 7bbaaf0

1 file changed

Lines changed: 90 additions & 16 deletions

File tree

docs/overrides/assets/javascripts/toggle.js

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,49 @@ document$.subscribe(function() {
3030
loadingOverlay.classList.remove("active");
3131
};
3232

33-
// Find the best anchor element and calculate offset from it
33+
// Find the tab container currently visible in the viewport
3434
const findScrollAnchor = () => {
35-
const headings = document.querySelectorAll('.md-content__inner h1, .md-content__inner h2, .md-content__inner h3, .md-content__inner h4, .md-content__inner h5, .md-content__inner h6');
36-
const currentScrollY = window.scrollY;
3735
const headerOffset = 80; // Account for sticky header
36+
const viewportTop = window.scrollY + headerOffset;
37+
const viewportCenter = viewportTop + (window.innerHeight / 3); // Upper third of visible area
38+
39+
// First, try to find a tabbed container that's currently in view
40+
const tabbedContainers = document.querySelectorAll('.md-typeset .tabbed-set');
41+
let bestContainer = null;
42+
let bestDistance = Infinity;
43+
44+
for (const container of tabbedContainers) {
45+
const rect = container.getBoundingClientRect();
46+
const containerTop = rect.top + window.scrollY;
47+
const containerBottom = containerTop + rect.height;
48+
49+
// Check if this container is visible in the viewport
50+
if (containerBottom > viewportTop && containerTop < viewportTop + window.innerHeight) {
51+
// Find the container closest to the top of the viewport
52+
const distance = Math.abs(containerTop - viewportTop);
53+
if (distance < bestDistance) {
54+
bestDistance = distance;
55+
bestContainer = container;
56+
}
57+
}
58+
}
59+
60+
if (bestContainer) {
61+
const containerTop = bestContainer.getBoundingClientRect().top + window.scrollY;
62+
return {
63+
element: bestContainer,
64+
offset: window.scrollY - containerTop,
65+
type: 'tabbed-set'
66+
};
67+
}
3868

69+
// Fallback: find the nearest heading
70+
const headings = document.querySelectorAll('.md-content__inner h1, .md-content__inner h2, .md-content__inner h3, .md-content__inner h4, .md-content__inner h5, .md-content__inner h6');
3971
let anchorElement = null;
4072

41-
// Find the last heading that is above or at the current scroll position
4273
for (const heading of headings) {
4374
const headingTop = heading.getBoundingClientRect().top + window.scrollY;
44-
if (headingTop <= currentScrollY + headerOffset + 50) {
75+
if (headingTop <= viewportCenter) {
4576
anchorElement = heading;
4677
} else {
4778
break;
@@ -52,7 +83,8 @@ document$.subscribe(function() {
5283
const anchorTop = anchorElement.getBoundingClientRect().top + window.scrollY;
5384
return {
5485
element: anchorElement,
55-
offset: currentScrollY - anchorTop
86+
offset: window.scrollY - anchorTop,
87+
type: 'heading'
5688
};
5789
}
5890

@@ -63,17 +95,28 @@ document$.subscribe(function() {
6395
const restoreScrollPosition = (anchor) => {
6496
if (!anchor || !anchor.element) return;
6597

66-
// Wait for DOM to reflow after tab switch
98+
// Wait for DOM to reflow after tab switch - use multiple frames for large content changes
6799
requestAnimationFrame(() => {
68100
requestAnimationFrame(() => {
69-
const newAnchorTop = anchor.element.getBoundingClientRect().top + window.scrollY;
70-
const newScrollY = newAnchorTop + anchor.offset;
71-
72-
window.scroll({
73-
top: Math.max(0, newScrollY),
74-
left: 0,
75-
behavior: "instant"
76-
});
101+
setTimeout(() => {
102+
const newAnchorTop = anchor.element.getBoundingClientRect().top + window.scrollY;
103+
104+
// For tabbed containers, scroll to show the container at the same relative position
105+
// For headings, restore the exact offset
106+
let newScrollY;
107+
if (anchor.type === 'tabbed-set') {
108+
// Keep the container at roughly the same position relative to viewport top
109+
newScrollY = newAnchorTop + Math.min(anchor.offset, 0);
110+
} else {
111+
newScrollY = newAnchorTop + anchor.offset;
112+
}
113+
114+
window.scroll({
115+
top: Math.max(0, newScrollY),
116+
left: 0,
117+
behavior: "instant"
118+
});
119+
}, 50); // Additional delay for large DOM changes
77120
});
78121
});
79122
};
@@ -110,6 +153,33 @@ document$.subscribe(function() {
110153
switchToTab(initialLang, false, null);
111154
});
112155

156+
// Flag to prevent circular updates when we programmatically click tabs
157+
let isToggleSwitching = false;
158+
159+
// Sync toggle button state based on which tab is active
160+
const syncToggleState = (tabName) => {
161+
if (isToggleSwitching) return; // Don't sync if we triggered the change
162+
163+
const isYaml = tabName.toLowerCase() === LANG_B.toLowerCase();
164+
if (switchInput.checked !== isYaml) {
165+
switchInput.checked = isYaml;
166+
localStorage.setItem(STORAGE_KEY, isYaml ? LANG_B : LANG_A);
167+
}
168+
};
169+
170+
// Listen for clicks on tab labels to sync toggle state
171+
const tabLabels = document.querySelectorAll(".md-typeset .tabbed-labels > label");
172+
tabLabels.forEach(label => {
173+
label.addEventListener("click", () => {
174+
const tabName = label.textContent.trim();
175+
// Only sync if it's a Table or YAML tab
176+
if (tabName.toLowerCase() === LANG_A.toLowerCase() ||
177+
tabName.toLowerCase() === LANG_B.toLowerCase()) {
178+
syncToggleState(tabName);
179+
}
180+
});
181+
});
182+
113183
if (!switchInput.hasAttribute('data-listener-attached')) {
114184
switchInput.addEventListener("change", (event) => {
115185
const targetLang = event.target.checked ? LANG_B : LANG_A;
@@ -120,13 +190,17 @@ document$.subscribe(function() {
120190
// Show loading spinner
121191
showLoading();
122192

193+
// Set flag to prevent circular sync
194+
isToggleSwitching = true;
195+
123196
// Use setTimeout to allow the spinner to render before switching tabs
124197
setTimeout(() => {
125198
switchToTab(targetLang, true, scrollAnchor);
126199
localStorage.setItem(STORAGE_KEY, targetLang);
127200

128-
// Hide loading spinner after scroll restoration completes
201+
// Reset flag after tabs have switched
129202
setTimeout(() => {
203+
isToggleSwitching = false;
130204
hideLoading();
131205
}, 100);
132206
}, 50);

0 commit comments

Comments
 (0)