403Webshell
Server IP : 37.9.174.138  /  Your IP : 216.73.216.117
Web Server : Apache
System : Linux vps6.backend.sk 6.12.100+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.100-1 (2026-07-30) x86_64
User : ftpuser ( 1001)
PHP Version : 8.4.24
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/html/backend-accounting.sk/app/modules/documentation/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/backend-accounting.sk/app/modules/documentation/view.php
<?php

declare(strict_types=1);

/**
 * UTF-8 HTML view of a module markdown doc (Bootstrap 5 docs layout).
 *
 * URL: /modules/documentation/view.php?md={module}/docs/{file}.md
 * Example: /modules/documentation/view.php?md=worksheets/docs/MESACNA-KONTROLA.md
 *
 * Access: logged-in staff only (not customers).
 */

session_start();

$ROOT_FOLDER = 'modules';
$_SERVER['DOCUMENT_ROOT'] = substr(__DIR__, 0, strpos(__DIR__, $ROOT_FOLDER));

require $_SERVER['DOCUMENT_ROOT'] . 'config.php';
require $_SERVER['DOCUMENT_ROOT'] . 'app/classes/App.php';
require $_SERVER['DOCUMENT_ROOT'] . 'vendor/autoload.php';
App::run();

try {
    $user = \app\classes\BasicUser::getLoggedUser();
    if ($user->isCustomer()) {
        throw new \Exception('Forbidden', \app\constants\HttpReponseCodes::HTTP_FORBIDDEN);
    }
} catch (\Exception $ex) {
    header('HTTP/1.0 403 Forbidden');
    header('Content-Type: text/plain; charset=UTF-8');
    echo 'Prístup zamietnutý.';
    exit;
}

$mdRel = isset($_GET['md']) ? (string) $_GET['md'] : '';
$mdRel = str_replace('\\', '/', $mdRel);
$mdRel = ltrim($mdRel, '/');

if (!preg_match('#^[a-zA-Z0-9_-]+/docs/[a-zA-Z0-9_.-]+\.md$#', $mdRel)) {
    header('Content-Type: text/plain; charset=UTF-8', true, 404);
    echo 'Dokument sa nenašiel.';
    exit;
}

$projectRoot = rtrim((string) $_SERVER['DOCUMENT_ROOT'], '/\\');
$modulesRoot = $projectRoot . DIRECTORY_SEPARATOR . 'modules';
$mdPath = $modulesRoot . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $mdRel);
$mdReal = realpath($mdPath);
$modulesReal = realpath($modulesRoot);

if (
    $mdReal === false
    || $modulesReal === false
    || strpos($mdReal, $modulesReal . DIRECTORY_SEPARATOR) !== 0
    || !is_readable($mdReal)
) {
    header('Content-Type: text/plain; charset=UTF-8', true, 404);
    echo 'Dokument sa nenašiel.';
    exit;
}

header('Content-Type: text/html; charset=UTF-8');

/**
 * @return array{
 *   introHtml: string,
 *   sections: list<array{id: string, title: string, bodyHtml: string}>,
 *   nav: list<array{id: string, text: string, level: int}>
 * }
 */
function documentationDocsParseMarkdown(string $md): array
{
    $lines = preg_split('/\r\n|\r|\n/', $md) ?: [];
    $nav = [];
    $usedIds = [];
    $introParts = [];
    $sections = [];
    $currentSection = null;
    $i = 0;
    $n = count($lines);
    $skipFirstH1 = true;

    $append = static function (string $html) use (&$introParts, &$currentSection): void {
        if ($currentSection === null) {
            $introParts[] = $html;
            return;
        }
        $currentSection['bodyParts'][] = $html;
    };

    $closeSection = static function () use (&$sections, &$currentSection): void {
        if ($currentSection === null) {
            return;
        }
        $sections[] = [
            'id' => $currentSection['id'],
            'title' => $currentSection['title'],
            'bodyHtml' => implode("\n", $currentSection['bodyParts']),
        ];
        $currentSection = null;
    };

    while ($i < $n) {
        $line = $lines[$i];

        if ($line === '---') {
            $i++;
            continue;
        }

        if (preg_match('/^(#{1,6})\s+(.+)$/', $line, $m)) {
            $level = strlen($m[1]);
            $level = min(max($level, 1), 6);
            $plain = trim(strip_tags(preg_replace('/\*\*(.+?)\*\*/', '$1', $m[2]) ?? $m[2]));

            if ($level === 1 && $skipFirstH1) {
                $skipFirstH1 = false;
                $i++;
                continue;
            }

            $id = documentationDocsHeadingId($plain, $usedIds);
            $headingHtml = documentationDocsInline($m[2]);

            if ($level === 2) {
                $closeSection();
                $nav[] = [
                    'id' => $id,
                    'text' => $plain,
                    'level' => 2,
                ];
                $currentSection = [
                    'id' => $id,
                    'title' => $headingHtml,
                    'bodyParts' => [],
                ];
                $i++;
                continue;
            }

            if ($level === 3 || $level === 4 || $level === 5 || $level === 6) {
                if ($level === 3) {
                    $nav[] = [
                        'id' => $id,
                        'text' => $plain,
                        'level' => 3,
                    ];
                }
                $anchor = '<a class="docs-heading-anchor text-decoration-none" href="#'
                    . htmlspecialchars($id, ENT_QUOTES, 'UTF-8')
                    . '" aria-label="Odkaz na sekciu">#</a>';
                $append(
                    '<h' . $level . ' id="' . htmlspecialchars($id, ENT_QUOTES, 'UTF-8') . '" class="docs-heading">'
                    . $headingHtml . ' ' . $anchor
                    . '</h' . $level . '>'
                );
                $i++;
                continue;
            }

            $i++;
            continue;
        }

        if (preg_match('/^\|\s*.+\s*\|$/', $line)) {
            $tableLines = [];
            while ($i < $n && preg_match('/^\|\s*.+\s*\|$/', $lines[$i])) {
                $tableLines[] = $lines[$i];
                $i++;
            }
            $append(documentationDocsTable($tableLines));
            continue;
        }

        if (preg_match('/^-\s+(.+)$/', $line, $m)) {
            $items = [];
            while ($i < $n && preg_match('/^-\s+(.+)$/', $lines[$i], $lm)) {
                $items[] = '<li>' . documentationDocsInline($lm[1]) . '</li>';
                $i++;
            }
            $append('<ul class="mb-3">' . implode('', $items) . '</ul>');
            continue;
        }

        if (preg_match('/^\d+\.\s+(.+)$/', $line, $m)) {
            $items = [];
            while ($i < $n && preg_match('/^\d+\.\s+(.+)$/', $lines[$i], $lm)) {
                $items[] = '<li>' . documentationDocsInline($lm[1]) . '</li>';
                $i++;
            }
            $append('<ol class="mb-3">' . implode('', $items) . '</ol>');
            continue;
        }

        if (trim($line) === '') {
            $i++;
            continue;
        }

        $para = [];
        while ($i < $n && trim($lines[$i]) !== '' && !preg_match('/^(#{1,6}\s|-\s|\d+\.\s|\||---$)/', $lines[$i])) {
            $para[] = $lines[$i];
            $i++;
        }
        $append('<p class="mb-3">' . documentationDocsInline(implode(' ', $para)) . '</p>');
    }

    $closeSection();

    return [
        'introHtml' => implode("\n", $introParts),
        'sections' => $sections,
        'nav' => $nav,
    ];
}

/**
 * @param array<string, true> $usedIds
 */
function documentationDocsHeadingId(string $text, array &$usedIds): string
{
    $map = [
        'á' => 'a', 'ä' => 'a', 'č' => 'c', 'ď' => 'd', 'é' => 'e', 'í' => 'i',
        'ĺ' => 'l', 'ľ' => 'l', 'ň' => 'n', 'ó' => 'o', 'ô' => 'o', 'ŕ' => 'r',
        'š' => 's', 'ť' => 't', 'ú' => 'u', 'ý' => 'y', 'ž' => 'z',
        'Á' => 'a', 'Ä' => 'a', 'Č' => 'c', 'Ď' => 'd', 'É' => 'e', 'Í' => 'i',
        'Ĺ' => 'l', 'Ľ' => 'l', 'Ň' => 'n', 'Ó' => 'o', 'Ô' => 'o', 'Ŕ' => 'r',
        'Š' => 's', 'Ť' => 't', 'Ú' => 'u', 'Ý' => 'y', 'Ž' => 'z',
    ];
    $slug = strtr($text, $map);
    $slug = strtolower($slug);
    $slug = preg_replace('/[^a-z0-9]+/', '-', $slug) ?? 'sekcia';
    $slug = trim($slug, '-');
    if ($slug === '') {
        $slug = 'sekcia';
    }

    $base = $slug;
    $n = 2;
    while (isset($usedIds[$slug])) {
        $slug = $base . '-' . $n;
        $n++;
    }
    $usedIds[$slug] = true;

    return $slug;
}

function documentationDocsInline(string $text): string
{
    $text = htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    $text = preg_replace('/`([^`]+)`/', '<code class="docs-code">$1</code>', $text) ?? $text;
    $text = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $text) ?? $text;

    return $text;
}

function documentationDocsTable(array $tableLines): string
{
    if ($tableLines === []) {
        return '';
    }

    $rows = [];
    foreach ($tableLines as $rowLine) {
        $cells = array_map('trim', explode('|', trim($rowLine, '|')));
        $isSeparator = true;
        foreach ($cells as $cell) {
            if ($cell !== '' && !preg_match('/^:?-+:?$/', $cell)) {
                $isSeparator = false;
                break;
            }
        }
        if ($isSeparator) {
            continue;
        }
        $rows[] = $cells;
    }

    if ($rows === []) {
        return '';
    }

    $html = '<div class="table-responsive mb-3"><table class="table table-sm table-bordered table-striped align-middle docs-table mb-0">';
    $html .= '<thead><tr>';
    foreach ($rows[0] as $cell) {
        $html .= '<th scope="col">' . documentationDocsInline($cell) . '</th>';
    }
    $html .= '</tr></thead><tbody>';

    for ($r = 1, $rc = count($rows); $r < $rc; $r++) {
        $html .= '<tr>';
        foreach ($rows[$r] as $cell) {
            $html .= '<td>' . documentationDocsInline($cell) . '</td>';
        }
        $html .= '</tr>';
    }

    return $html . '</tbody></table></div>';
}

$md = (string) file_get_contents($mdReal);
$title = 'Dokumentácia';
if (preg_match('/^#\s+(.+)$/m', $md, $m)) {
    $title = trim($m[1]);
}

$parsed = documentationDocsParseMarkdown($md);
$introHtml = $parsed['introHtml'];
$sections = $parsed['sections'];
$navItems = $parsed['nav'];
?>
<!DOCTYPE html>
<html lang="sk">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?php echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); ?></title>
    <link href="/lib/bootstrap5/css/bootstrap.min.css" rel="stylesheet">
    <style>
        :root {
            --docs-accent: #0d6efd;
            --docs-accent-soft: #e7f1ff;
            --docs-accent-mid: #cfe2ff;
            --docs-accent-dark: #0a58ca;
            --docs-text: #495057;
            --docs-text-strong: #212529;
            --docs-bg: #f3f4f6;
        }

        body {
            background: var(--docs-bg);
            color: var(--docs-text);
        }

        .docs-layout {
            max-width: 1140px;
            margin: 0 auto;
        }

        /* Sticky TOC: own vertical scroll when taller than viewport (e.g. docs iframe modal). */
        .docs-sidebar {
            position: sticky;
            top: 1.25rem;
            align-self: start;
            max-height: calc(100vh - 2.5rem);
            overflow-x: hidden;
            overflow-y: auto;
            overscroll-behavior: contain;
            -webkit-overflow-scrolling: touch;
        }

        .docs-toc-card {
            background: #fff;
            border: 1px solid #e5e7eb;
            border-radius: 0.75rem;
            padding: 1rem;
            box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.04);
        }

        .docs-toc-title {
            font-size: 0.75rem;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            color: var(--docs-accent);
        }

        .docs-toc .nav-link {
            color: #495057;
            font-size: 0.9rem;
            padding: 0.35rem 0.75rem;
            border-left: 2px solid transparent;
            border-radius: 0;
            white-space: normal;
            word-break: break-word;
        }

        .docs-toc .nav-link.docs-toc-h2 {
            font-weight: 700;
            color: #212529;
        }

        .docs-toc .nav-link:hover,
        .docs-toc .nav-link:focus {
            color: var(--docs-accent);
            background: rgba(13, 110, 253, 0.06);
        }

        .docs-toc .nav-link.active {
            color: var(--docs-accent);
            font-weight: 700;
            border-left-color: var(--docs-accent);
            background: rgba(13, 110, 253, 0.08);
        }

        .docs-toc .nav-link.docs-toc-h3 {
            padding-left: 1.5rem;
            font-size: 0.85rem;
            color: #6c757d;
            font-weight: 400;
        }

        .docs-toc .nav-link.docs-toc-h3.active {
            font-weight: 600;
        }

        .docs-mobile-toc-bar {
            display: flex;
            justify-content: flex-end;
            margin-bottom: 1rem;
        }

        @media (min-width: 992px) {
            .docs-mobile-toc-bar {
                display: none;
            }
        }

        .docs-intro-card,
        .docs-section-card {
            border: 1px solid #e5e7eb;
            border-radius: 0.75rem;
            box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.04);
            overflow: hidden;
            background: #fff;
        }

        .docs-intro-card .card-body {
            padding: 1.35rem 1.75rem 1.6rem;
        }

        .docs-intro {
            color: var(--docs-text);
        }

        .docs-intro > :last-child,
        .docs-section-card .card-body > :last-child {
            margin-bottom: 0 !important;
        }

        .docs-intro strong {
            color: var(--docs-text-strong);
        }

        .docs-section-card {
            scroll-margin-top: 1.25rem;
        }

        .docs-section-card .card-header {
            background: linear-gradient(90deg, var(--docs-accent-soft) 0%, #f8fbff 100%);
            border-bottom: 1px solid var(--docs-accent-mid);
            padding: 0.95rem 1.35rem;
        }

        .docs-section-card .card-header h2 {
            font-size: 1.2rem;
            font-weight: 700;
            margin: 0;
            color: var(--docs-accent-dark);
            letter-spacing: -0.015em;
            scroll-margin-top: 1.25rem;
        }

        .docs-section-card .card-body {
            padding: 1.35rem 1.5rem 1.6rem;
            background: #fff;
            color: var(--docs-text);
            line-height: 1.6;
        }

        .docs-section-card .card-body > :last-child {
            margin-bottom: 0 !important;
        }

        .docs-section-card .card-body strong {
            color: var(--docs-text-strong);
            font-weight: 600;
        }

        .docs-section-card h3 {
            font-size: 1.02rem;
            font-weight: 700;
            margin-top: 1.5rem;
            margin-bottom: 0.7rem;
            padding: 0.35rem 0 0.35rem 0.8rem;
            border-top: none;
            border-left: 3px solid var(--docs-accent);
            color: #084298;
            background: transparent;
            scroll-margin-top: 1.25rem;
        }

        .docs-section-card h3:first-child {
            margin-top: 0.15rem;
            padding-top: 0.35rem;
        }

        .docs-section-card h4,
        .docs-section-card h5,
        .docs-section-card h6 {
            color: #0a58ca;
            font-weight: 600;
            margin-top: 1.1rem;
            margin-bottom: 0.55rem;
            scroll-margin-top: 1.25rem;
        }

        /* Explicit sizes: Bootstrap defaults make h4 larger than our custom h3 (1.02rem). */
        .docs-section-card h4 {
            font-size: 0.98rem;
        }

        .docs-section-card h5 {
            font-size: 0.94rem;
        }

        .docs-section-card h6 {
            font-size: 0.9rem;
        }

        .docs-section-card ul,
        .docs-section-card ol {
            padding-left: 1.2rem;
        }

        .docs-section-card li {
            margin-bottom: 0.35rem;
        }

        .docs-section-card li::marker {
            color: var(--docs-accent);
        }

        .docs-heading-anchor {
            opacity: 0;
            color: var(--docs-accent);
            font-weight: 400;
            margin-left: 0.25rem;
        }

        .docs-heading:hover .docs-heading-anchor,
        .docs-section-card .card-header:hover .docs-heading-anchor {
            opacity: 1;
        }

        .docs-code {
            background: var(--docs-accent-soft);
            color: var(--docs-accent-dark);
            padding: 0.12em 0.4em;
            border-radius: 0.25rem;
            font-size: 0.9em;
            border: 1px solid var(--docs-accent-mid);
        }

        .docs-table {
            font-size: 0.925rem;
            --bs-table-bg: #fff;
            --bs-table-striped-bg: #f9fafb;
            --bs-table-border-color: #e5e7eb;
            border: 1px solid #e5e7eb;
            border-radius: 0.5rem;
            overflow: hidden;
            color: var(--docs-text);
        }

        .docs-table.table-bordered > :not(caption) > * {
            border-width: 0;
        }

        .docs-table.table-bordered > :not(caption) > * > * {
            border: 1px solid var(--bs-table-border-color);
        }

        .docs-table.table-bordered > :first-child > tr:first-child > * {
            border-top-width: 0;
        }

        .docs-table.table-bordered > :last-child > tr:last-child > * {
            border-bottom-width: 0;
        }

        .docs-table.table-bordered > :not(caption) > * > *:first-child {
            border-left-width: 0;
        }

        .docs-table.table-bordered > :not(caption) > * > *:last-child {
            border-right-width: 0;
        }

        .docs-table thead th {
            white-space: nowrap;
            font-weight: 700;
            color: var(--docs-text-strong) !important;
            background: #f3f4f6 !important;
            border-bottom-color: #e5e7eb !important;
            box-shadow: none;
        }

        .docs-table thead th strong,
        .docs-table thead th code,
        .docs-table thead th a {
            color: var(--docs-text-strong) !important;
        }

        .docs-table thead th code {
            background: #fff;
            border: 1px solid #e5e7eb;
            padding: 0.05em 0.3em;
            border-radius: 0.2rem;
            font-weight: 600;
        }

        .docs-table tbody td {
            vertical-align: top;
        }

        .docs-offcanvas-toc .nav-link {
            border-left: 2px solid transparent;
        }

        .docs-offcanvas-toc .nav-link.active {
            border-left-color: var(--docs-accent);
            color: var(--docs-accent);
            font-weight: 700;
        }

        .btn-outline-secondary {
            --bs-btn-color: var(--docs-accent-dark);
            --bs-btn-border-color: var(--docs-accent-mid);
            --bs-btn-hover-bg: var(--docs-accent);
            --bs-btn-hover-border-color: var(--docs-accent);
            --bs-btn-hover-color: #fff;
            --bs-btn-active-bg: var(--docs-accent-dark);
            --bs-btn-active-border-color: var(--docs-accent-dark);
        }
    </style>
</head>
<body tabindex="0">
<div class="container-xxl docs-layout px-3 px-lg-4 py-4">
    <div class="docs-mobile-toc-bar">
        <button class="btn btn-outline-secondary btn-sm" type="button"
                data-bs-toggle="offcanvas" data-bs-target="#docsOffcanvas"
                aria-controls="docsOffcanvas">
            Obsah
        </button>
    </div>

    <div class="row g-4">
        <aside class="col-lg-3 d-none d-lg-block">
            <nav id="docsToc" class="docs-sidebar" aria-label="Obsah dokumentu">
                <div class="docs-toc-card">
                    <div class="docs-toc-title mb-2">Obsah</div>
                    <nav class="nav flex-column docs-toc">
                        <?php foreach ($navItems as $item): ?>
                            <a class="nav-link<?php echo $item['level'] === 3 ? ' docs-toc-h3' : ' docs-toc-h2'; ?>"
                               href="#<?php echo htmlspecialchars($item['id'], ENT_QUOTES, 'UTF-8'); ?>">
                                <?php echo htmlspecialchars($item['text'], ENT_QUOTES, 'UTF-8'); ?>
                            </a>
                        <?php endforeach; ?>
                    </nav>
                </div>
            </nav>
        </aside>

        <main class="col-lg-9">
            <div class="d-flex flex-column gap-3">
                <?php if ($introHtml !== ''): ?>
                    <div class="card docs-intro-card">
                        <div class="card-body">
                            <div class="docs-intro">
                                <?php echo $introHtml; ?>
                            </div>
                        </div>
                    </div>
                <?php endif; ?>

                <?php foreach ($sections as $section): ?>
                    <section class="card docs-section-card" id="<?php echo htmlspecialchars($section['id'], ENT_QUOTES, 'UTF-8'); ?>">
                        <div class="card-header">
                            <h2 class="docs-heading">
                                <?php echo $section['title']; ?>
                                <a class="docs-heading-anchor text-decoration-none"
                                   href="#<?php echo htmlspecialchars($section['id'], ENT_QUOTES, 'UTF-8'); ?>"
                                   aria-label="Odkaz na sekciu">#</a>
                            </h2>
                        </div>
                        <div class="card-body">
                            <?php echo $section['bodyHtml']; ?>
                        </div>
                    </section>
                <?php endforeach; ?>
            </div>
        </main>
    </div>
</div>

<div class="offcanvas offcanvas-start" tabindex="-1" id="docsOffcanvas" aria-labelledby="docsOffcanvasLabel">
    <div class="offcanvas-header border-bottom">
        <h2 class="offcanvas-title fs-5" id="docsOffcanvasLabel">Obsah</h2>
        <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Zavrieť"></button>
    </div>
    <div class="offcanvas-body">
        <nav class="nav flex-column docs-toc docs-offcanvas-toc">
            <?php foreach ($navItems as $item): ?>
                <a class="nav-link<?php echo $item['level'] === 3 ? ' docs-toc-h3' : ' docs-toc-h2'; ?>"
                   href="#<?php echo htmlspecialchars($item['id'], ENT_QUOTES, 'UTF-8'); ?>"
                   data-bs-dismiss="offcanvas">
                    <?php echo htmlspecialchars($item['text'], ENT_QUOTES, 'UTF-8'); ?>
                </a>
            <?php endforeach; ?>
        </nav>
    </div>
</div>

<script src="/lib/bootstrap5/js/bootstrap.bundle.min.js"></script>
<script>
(function () {
    var links = Array.prototype.slice.call(document.querySelectorAll('.docs-toc .nav-link'));
    if (!links.length) {
        return;
    }

    var byId = {};
    links.forEach(function (link) {
        var href = link.getAttribute('href') || '';
        if (href.charAt(0) !== '#') {
            return;
        }
        var id = href.slice(1);
        if (!id) {
            return;
        }
        if (!byId[id]) {
            byId[id] = {
                id: id,
                el: document.getElementById(id),
                links: []
            };
        }
        byId[id].links.push(link);
    });

    var sections = Object.keys(byId).map(function (id) {
        return byId[id];
    }).filter(function (item) {
        return !!item.el;
    }).sort(function (a, b) {
        if (a.el === b.el) {
            return 0;
        }
        return (a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1;
    });

    if (!sections.length) {
        return;
    }

    var offset = 96;
    var sidebar = document.getElementById('docsToc');
    var lastActiveId = '';

    function ensureSidebarLinkVisible(link) {
        if (!sidebar || !link || !sidebar.contains(link)) {
            return;
        }
        var sidebarRect = sidebar.getBoundingClientRect();
        var linkRect = link.getBoundingClientRect();
        var pad = 8;
        if (linkRect.top < sidebarRect.top + pad) {
            sidebar.scrollTop += linkRect.top - sidebarRect.top - pad;
        } else if (linkRect.bottom > sidebarRect.bottom - pad) {
            sidebar.scrollTop += linkRect.bottom - sidebarRect.bottom + pad;
        }
    }

    function setActive() {
        var current = sections[0];
        for (var i = 0; i < sections.length; i++) {
            if (sections[i].el.getBoundingClientRect().top <= offset) {
                current = sections[i];
            }
        }

        links.forEach(function (link) {
            link.classList.remove('active');
        });
        current.links.forEach(function (link) {
            link.classList.add('active');
        });

        if (current.id !== lastActiveId) {
            lastActiveId = current.id;
            var sidebarLink = current.links.filter(function (link) {
                return sidebar && sidebar.contains(link);
            })[0];
            ensureSidebarLinkVisible(sidebarLink);
        }
    }

    var ticking = false;
    window.addEventListener('scroll', function () {
        if (ticking) {
            return;
        }
        ticking = true;
        window.requestAnimationFrame(function () {
            setActive();
            ticking = false;
        });
    }, {passive: true});

    window.addEventListener('resize', setActive);
    setActive();
})();
</script>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit