BDO Navigator: Quick Access TOC

Interactive side Table of Contents for Black Desert. Provides instant navigation through patch note sections.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         BDO Navigator: Quick Access TOC
// @name:ru      BDO Navigator: Быстрое Содержание
// @name:ko      BDO 나침반: 빠른 목차 이동
// @name:tr      BDO Gezgini: Hızlı İçerik Menüsü
// @namespace    Sandr
// @version      1.1
// @description  Interactive side Table of Contents for Black Desert. Provides instant navigation through patch note sections.
// @description:ru Интерактивное боковое оглавление для Black Desert. Мгновенная навигация по разделам патчноута.
// @description:ko 검은사막 뉴스 페이지를 위한 인터랙티브 측면 목차. 패치 노트의 각 섹션으로 즉시 이동할 수 있습니다.
// @description:tr Black Desert için interaktif yan içerik tablosu. Yama notu bölümleri arasında anında gezinme sağlar.
// @description:de Interaktives seitliches Inhaltsverzeichnis für Black Desert. Ermöglicht die sofortige Navigation durch die Patch-Note-Abschnitte.
// @description:fr Table des matières latérale interactive pour Black Desert. Permet une navigation instantanée dans les sections des notes de patch.
// @description:es Tabla de contenidos lateral interactiva para Black Desert. Permite la navegación instantánea por las secciones de las notas del parche.
// @description:pt Tabela de conteúdos lateral interativa para o Black Desert. Permite a navegação instantânea pelas seções das notas de atualização.
// @description:th สารบัญด้านข้างแบบโต้ตอบสำหรับ Black Desert ช่วยให้เลื่อนไปยังส่วนต่างๆ ของแพตช์โน้ตได้อย่างรวดเร็ว
// @description:zh-tw 黑沙漠互動式側邊目錄。提供更新日誌章節 delivery 的快速導覽。
// @author       Sandr
// @match        https://*.playblackdesert.com/*/News/Detail*
// @match        https://*.playblackdesert.com/News/Notice/Detail*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=playblackdesert.com
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const init = () => {
        if (document.getElementById('bdo-quick-nav')) return;

        // 1. Ищем оригинальное оглавление (список ol)
        let originalToc = document.querySelector('.news_area ol') ||
                          document.querySelector('.contents_area ol') ||
                          document.querySelector('ol[data-maxwidthlimited="true"]');

        if (!originalToc) {
            // Запасной вариант: ищем ссылки-якоря, если ol не найден
            const anchors = document.querySelectorAll('.news_area a[href^="#"], .contents_area a[href^="#"]');
            if (anchors.length > 3) {
                originalToc = document.createElement('ol');
                anchors.forEach(a => {
                    const li = document.createElement('li');
                    li.appendChild(a.cloneNode(true));
                    originalToc.appendChild(li);
                });
            }
        }

        if (!originalToc) {
            setTimeout(init, 2000);
            return;
        }

        // 2. Ищем текст заголовка прямо на странице (h3 над оглавлением)
        let headerText = "Содержание"; // Значение по умолчанию
        const pageHeader = document.querySelector('h3[data-maxwidthlimited="true"]');
        if (pageHeader) {
            headerText = pageHeader.innerText.trim();
        }

        // 3. Стили (дизайн v1.5)
        const style = document.createElement('style');
        style.innerHTML = `
            #bdo-quick-nav {
                position: fixed !important;
                left: 0 !important;
                top: 15% !important;
                z-index: 999999 !important;
                display: flex !important;
                align-items: flex-start !important;
                font-family: "Noto Sans KR", sans-serif !important;
            }

            #bdo-nav-trigger {
                width: 32px; height: 54px;
                background: #1c1c22; color: #cebb9a;
                display: flex; align-items: center; justify-content: center;
                cursor: pointer; border: 1px solid #3d3d47; border-left: none;
                border-radius: 0 6px 6px 0; box-shadow: 4px 0 12px rgba(0,0,0,0.4);
                font-size: 20px;
            }

            #bdo-nav-panel {
                width: 300px; max-height: 75vh;
                background: #1c1c22; border: 1px solid #3d3d47;
                padding: 16px; overflow-y: auto;
                box-shadow: 8px 8px 24px rgba(0,0,0,0.6);
                display: none;
            }

            .bdo-nav-header {
                color: #cebb9a; font-weight: bold;
                border-bottom: 1px solid #3d3d47;
                margin-bottom: 12px; padding-bottom: 8px;
                text-transform: uppercase; font-size: 14px;
                letter-spacing: 0.5px;
            }

            #bdo-nav-panel ol { list-style: none !important; padding: 0 !important; margin: 0 !important; }
            #bdo-nav-panel li { margin-bottom: 10px !important; line-height: 1.3 !important; }
            #bdo-nav-panel a {
                color: #cfcfcf !important; text-decoration: none !important;
                font-size: 13.5px !important; transition: all 0.15s ease;
                display: block;
            }
            #bdo-nav-panel a:hover { color: #f0e1c5 !important; transform: translateX(4px); }
            #bdo-nav-panel ol ol { padding-left: 18px !important; margin-top: 8px !important; border-left: 1px solid #333; }

            #bdo-quick-nav:hover #bdo-nav-panel { display: block; }
            #bdo-quick-nav:hover #bdo-nav-trigger { display: none; }

            #bdo-nav-panel::-webkit-scrollbar { width: 4px; }
            #bdo-nav-panel::-webkit-scrollbar-thumb { background: #cebb9a; }
        `;
        document.head.appendChild(style);

        // 4. Сборка меню
        const container = document.createElement('div');
        container.id = 'bdo-quick-nav';
        const trigger = document.createElement('div');
        trigger.id = 'bdo-nav-trigger';
        trigger.innerHTML = '☰';
        const panel = document.createElement('div');
        panel.id = 'bdo-nav-panel';
        panel.innerHTML = `<div class="bdo-nav-header">${headerText}</div>`;

        const clonedContent = originalToc.cloneNode(true);
        panel.appendChild(clonedContent);

        container.appendChild(trigger);
        container.appendChild(panel);
        document.body.appendChild(container);

        // 5. Логика переходов
        panel.querySelectorAll('a').forEach(link => {
            link.onclick = (e) => {
                const href = link.getAttribute('href');
                if (href && href.includes('#')) {
                    e.preventDefault();
                    const targetId = decodeURIComponent(href.split('#')[1]);
                    const target = document.getElementById(targetId) ||
                                 document.querySelector(`a[name="${targetId}"]`) ||
                                 document.getElementsByName(targetId)[0];

                    if (target) {
                        window.scrollTo({
                            top: target.getBoundingClientRect().top + window.pageYOffset - 40,
                            behavior: 'auto'
                        });
                    }
                }
            };
        });
    };

    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();