PageSourceSearch

https://vestnikkui.ru/bundles/journals/js/publication-detail/journal-tabs.js?v=20260929-journal-bar

js vestnikkui.ru collected 2026-10-02 20:02:58 UTC 6,746 bytes, 198 lines download raw bytes

1(function (window, document) {
2    var modules = window.EditorumPublicationDetailModules = window.EditorumPublicationDetailModules || {};
3    var shared = modules.shared || {};
4    var journal = modules.journal = modules.journal || {};
5
6    var queryAll = shared.queryAll;
7    var parseQuery = shared.parseQuery;
8    var getQueryParam = shared.getQueryParam;
9    var getHashId = shared.getHashId;
10    var getHashIdFromHref = shared.getHashIdFromHref;
11    var updateUrlState = shared.updateUrlState;
12
13    function initJournalTabs(options) {
14        var settings = options || {};
15        var tabRoot = document.querySelector(settings.rootSelector || '.journal-tabs-bar__nav');
16        var tabs = tabRoot ? queryAll(settings.linkSelector || '.journal-tabs-bar__link', tabRoot) : [];
17        var panels = queryAll(settings.panelSelector || '.journal-page .journal-tab-panel');
18        var queryParam = settings.queryParam || 'section';
19        var aliases = settings.aliases || {};
20        var defaultSection = settings.defaultSection || 'fresh';
21        var initialSection = settings.initialSection || defaultSection;
22        var knownSections = {};
23
24        function normalizeSection(sectionId) {
25            if (!sectionId) {
26                return '';
27            }
28
29            return aliases[sectionId] || sectionId;
30        }
31
32        function getSectionFromHref(href) {
33            var value = href || '';
34            var hashIndex = value.indexOf('#');
35            var queryIndex = value.indexOf('?');
36            var queryValue = null;
37            var query;
38
39            if (queryIndex !== -1) {
40                query = value.slice(queryIndex, hashIndex === -1 ? value.length : hashIndex);
41                queryValue = parseQuery(query)[queryParam] || null;
42            }
43
44            // The default section's link carries no ?section=, like the page URL it opens.
45            return normalizeSection(queryValue || getHashIdFromHref(value)) || defaultSection;
46        }
47
48        function resolveRequestedSection() {
49            var requestedSection = normalizeSection(getQueryParam(queryParam) || getHashId(window.location.hash) || initialSection || defaultSection);
50
51            if (requestedSection && knownSections[requestedSection]) {
52                return requestedSection;
53            }
54
55            if (knownSections[defaultSection]) {
56                return defaultSection;
57            }
58
59            return '';
60        }
61
62        function getPanelBySection(sectionId) {
63            var normalizedSection = normalizeSection(sectionId);
64            var match = null;
65
66            panels.some(function (panel) {
67                if (normalizeSection(panel.getAttribute('data-section-panel')) === normalizedSection) {
68                    match = panel;
69                    return true;
70                }
71
72                return false;
73            });
74
75            return match;
76        }
77
78        function panelHasRenderedContent(sectionId) {
79            var panel = getPanelBySection(sectionId);
80
81            if (!panel) {
82                return false;
83            }
84
85            return Array.prototype.some.call(panel.childNodes, function (node) {
86                if (node.nodeType === 1) {
87                    return true;
88                }
89
90                return node.nodeType === 3 && node.textContent.trim().length > 0;
91            });
92        }
93
94        function activateSection(sectionId, writeUrl) {
95            var normalizedSection = normalizeSection(sectionId) || defaultSection;
96
97            tabs.forEach(function (tab) {
98                var tabSection = getSectionFromHref(tab.getAttribute('href') || '');
99                var isActive = tabSection === normalizedSection;
100
101                tab.classList.toggle('active', isActive);
102                tab.setAttribute('aria-selected', isActive ? 'true' : 'false');
103            });
104
105            panels.forEach(function (panel) {
106                var isActive = panel.getAttribute('data-section-panel') === normalizedSection;
107
108                panel.classList.toggle('is-active', isActive);
109                panel.setAttribute('aria-hidden', isActive ? 'false' : 'true');
110                panel.hidden = !isActive;
111            });
112
113            if (writeUrl) {
114                updateUrlState((function () {
115                    var state = {};
116
117                    state[queryParam] = normalizedSection;
118
119                    return state;
120                })(), '', false);
121            }
122
123            return true;
124        }
125
126        if (!tabs.length) {
127            return false;
128        }
129
130        tabs.forEach(function (tab) {
131            var section = getSectionFromHref(tab.getAttribute('href') || '');
132
133            if (section) {
134                knownSections[section] = true;
135            }
136        });
137
138        panels.forEach(function (panel) {
139            var section = normalizeSection(panel.getAttribute('data-section-panel'));
140
141            if (section) {
142                knownSections[section] = true;
143            }
144        });
145
146        // A fragment naming another section was already turned into ?section= by the journal page
147        // <head>; reloading from here would show the default section first.
148        var initialResolvedSection = resolveRequestedSection();
149        var queryValue = getQueryParam(queryParam);
150
151        if (queryValue !== null && !knownSections[normalizeSection(queryValue)]) {
152            updateUrlState((function () {
153                var state = {};
154
155                state[queryParam] = '';
156
157                return state;
158            })(), undefined, true);
159        }
160
161        activateSection(initialResolvedSection, false);
162
163        if (window.location.hash) {
164            var normalizedHashSection = normalizeSection(getHashId(window.location.hash));
165
166            if (normalizedHashSection && knownSections[normalizedHashSection]) {
167                updateUrlState((function () {
168                    var state = {};
169
170                    state[queryParam] = initialResolvedSection || defaultSection;
171
172                    return state;
173                })(), '', true);
174            }
175        }
176
177        tabs.forEach(function (tab) {
178            tab.addEventListener('click', function (event) {
179                var targetSection = getSectionFromHref(tab.getAttribute('href') || '');
180
181                if (!panelHasRenderedContent(targetSection)) {
182                    return;
183                }
184
185                event.preventDefault();
186                activateSection(targetSection, true);
187            });
188        });
189
190        window.addEventListener('popstate', function () {
191            activateSection(resolveRequestedSection(), false);
192        });
193
194        return true;
195    }
196
197    journal.initJournalTabs = initJournalTabs;
198})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.