<script>
(function () {
const CONFIG = {
clickDelay: 50,
tabActivationDelay: 150,
scrollStabilityDelay: 50,
scrollMaxRetries: 8,
fullPageLoadDelay: 300,
maxAttempts: 30,
attemptInterval: 200
};
let isNavigatingFromClick = false;
function processTabLink(href) {
if (!href || typeof href !== 'string') return null;
const tabMarker = '#!/tab/';
const markerIndex = href.indexOf(tabMarker);
if (markerIndex === -1) return null;
const afterMarker = href.substring(markerIndex + tabMarker.length);
let firstEntry = afterMarker.split('&')[0];
firstEntry = firstEntry.split('#')[0];
firstEntry = firstEntry.split('?')[0];
if (!firstEntry) return null;
const parts = firstEntry.split('-');
if (parts.length < 2) return null;
const recID = parts[0];
const tabNum = parts[1];
return { recID, tabNum, fullEntry: firstEntry };
}
async function scrollToTabParentWithWait(element) {
const parentTRec = element.closest('.t-rec');
if (!parentTRec) {
console.error('Родитель .t-rec не найден');
return false;
}
const getElementPosition = () => {
const rect = parentTRec.getBoundingClientRect();
return {
top: rect.top + window.pageYOffset,
height: rect.height
};
};
let lastPosition = getElementPosition();
let stableCount = 0;
for (let i = 0; i < CONFIG.scrollMaxRetries; i++) {
await new Promise(resolve => setTimeout(resolve, CONFIG.scrollStabilityDelay));
const currentPosition = getElementPosition();
const isStable = Math.abs(currentPosition.top - lastPosition.top) < 5 &&
Math.abs(currentPosition.height - lastPosition.height) < 5;
if (isStable) {
stableCount++;
if (stableCount >= 2) {
parentTRec.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
return true;
}
} else {
stableCount = 0;
}
lastPosition = currentPosition;
}
parentTRec.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
return true;
}
async function performNavigation(recID, tabNum, shouldClick = true) {
if (!recID || !tabNum) return false;
const targetElement = document.querySelector(`#tab${tabNum}_${recID}`);
if (!targetElement) {
console.error(`Элемент #tab${tabNum}_${recID} не найден`);
return false;
}
if (shouldClick) {
targetElement.click();
await new Promise(resolve => setTimeout(resolve, CONFIG.tabActivationDelay));
}
await scrollToTabParentWithWait(targetElement);
return true;
}
function waitForFullPageLoad() {
return new Promise((resolve) => {
if (document.readyState === 'complete') {
setTimeout(resolve, CONFIG.fullPageLoadDelay);
} else {
window.addEventListener('load', () => {
setTimeout(resolve, CONFIG.fullPageLoadDelay);
});
}
});
}
async function handleInitialUrl() {
if (isNavigatingFromClick) return;
const currentUrl = window.location.href;
const result = processTabLink(currentUrl);
if (!result) return;
const { recID, tabNum } = result;
await waitForFullPageLoad();
const checkElementsAndNavigate = async () => {
const targetElement = document.querySelector(`#tab${tabNum}_${recID}`);
if (targetElement) {
await performNavigation(recID, tabNum, false);
return true;
}
return false;
};
if (await checkElementsAndNavigate()) return;
let attempts = 0;
const intervalId = setInterval(async () => {
attempts++;
if (await checkElementsAndNavigate()) {
clearInterval(intervalId);
} else if (attempts >= CONFIG.maxAttempts) {
clearInterval(intervalId);
console.error('Не удалось найти элемент');
}
}, CONFIG.attemptInterval);
const observer = new MutationObserver(async (mutations, obs) => {
if (await checkElementsAndNavigate()) {
obs.disconnect();
clearInterval(intervalId);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(() => observer.disconnect(), 10000);
}
function setupLinkTracking() {
document.addEventListener('click', async function(event) {
const link = event.target.closest('a');
if (!link) return;
const href = link.getAttribute('href');
if (!href) return;
let fullUrl;
try {
fullUrl = new URL(href, window.location.href).href;
} catch (e) {
fullUrl = href;
}
const result = processTabLink(fullUrl);
if (!result) return;
isNavigatingFromClick = true;
event.preventDefault();
const { recID, tabNum } = result;
try {
await new Promise(resolve => setTimeout(resolve, CONFIG.clickDelay));
await performNavigation(recID, tabNum, true);
} finally {
setTimeout(() => {
isNavigatingFromClick = false;
}, 500);
}
});
}
function setupUrlObserver() {
let lastUrl = window.location.href;
const observeUrlChanges = () => {
const currentUrl = window.location.href;
if (currentUrl !== lastUrl) {
lastUrl = currentUrl;
if (!isNavigatingFromClick && currentUrl.includes('#!/tab/')) {
handleInitialUrl();
}
}
};
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function() {
originalPushState.apply(this, arguments);
observeUrlChanges();
};
history.replaceState = function() {
originalReplaceState.apply(this, arguments);
observeUrlChanges();
};
window.addEventListener('popstate', observeUrlChanges);
}
function init() {
setupLinkTracking();
handleInitialUrl();
setupUrlObserver();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>