PageSourceSearch

https://mlhs.ink/Journal/plugins/themes/mycustom/js/main20.js?v=3.4.0.4

js mlhs.ink collected 2026-09-28 10:56:10 UTC 11,638 bytes, 278 lines download raw bytes

1/**
2 * @file plugins/themes/mycustom/js/main.js
3 *
4 * @brief Handle JavaScript functionality unique to My Custom Theme, including tab toggling, dark mode toggle, menu toggle, and copy-to-clipboard.
5 */
6(function($) {
7
8    // Existing code for dropdowns and nav menu...
9
10    // Tab functionality for About, Online First, and Current Issue
11    function switchTab(targetTab) {
12        $('.tab-content').hide(); // Hide all tab content
13        $('#' + targetTab).show(); // Show the selected tab content
14
15        $('.tabs li').removeClass('active');
16        $('.tabs a[href="#' + targetTab + '"]').parent().addClass('active');
17    }
18
19    $(document).ready(function() {
20
21        /* ---------------- Tabs: open from hash ONLY (paginator), otherwise default About ---------------- */
22        const $tabLinks = $('.tabs a[href^="#"]');
23
24        function setActiveByHref(href) {
25            if (typeof href !== 'string' || href.length < 2 || href.charAt(0) !== '#') return false;
26            const targetTab = href.substring(1);
27            if (!document.getElementById(targetTab)) return false;
28            switchTab(targetTab);
29            return true;
30        }
31
32        function clearHashKeepQuery() {
33            try {
34                if (history && history.replaceState) {
35                    history.replaceState(null, '', window.location.pathname + window.location.search);
36                } else {
37                    // fallback: best-effort
38                    window.location.hash = '';
39                }
40            } catch (e) {}
41        }
42
43        if ($tabLinks.length) {
44
45            // Click tabs: just switch UI. Do NOT persist across reload.
46            $tabLinks.on('click', function(e) {
47                e.preventDefault();
48                const href = $(this).attr('href');
49                setActiveByHref(href);
50
51                // If the user landed here via paginator hash, remove it after they interact
52                clearHashKeepQuery();
53            });
54
55            // On load: if paginator hash exists, open it ONCE, then clear hash so reload returns to About
56            const openedFromHash = setActiveByHref(window.location.hash);
57            if (openedFromHash) {
58                clearHashKeepQuery();
59            } else {
60                // Default behavior on any normal load/reload
61                switchTab('about');
62            }
63        }
64        /* ---------------- end tabs ---------------- */
65
66        // URL modification for issue links
67        const issueLinks = document.querySelectorAll('.issue_list a');
68        issueLinks.forEach(link => {
69            try {
70                const url = new URL(link.href);
71                const pathSegments = url.pathname.split('/');
72
73                // Check if URL structure matches the pattern `.../Web3/1`
74                if (pathSegments.length > 4 && pathSegments[4] === '1') {
75                    // Modify the path to `.../Web3/issue/view/1`
76                    pathSegments.splice(4, 0, 'issue', 'view');
77                    url.pathname = pathSegments.join('/');
78
79                    // Update the link href
80                    link.href = url.toString();
81                }
82            } catch (e) {
83                // ignore invalid URLs
84            }
85        });
86
87        // Dark Mode Toggle Functionality
88        const body = document.body;
89        const themeToggleButton = document.getElementById("themeToggleButton");
90
91        if (themeToggleButton) {
92            // Check local storage for theme preference
93            const savedTheme = localStorage.getItem("theme");
94            if (savedTheme === "dark") {
95                body.classList.add("dark-mode");
96                themeToggleButton.textContent = "☀️"; // Sun icon for light mode
97            } else {
98                themeToggleButton.textContent = "🌙"; // Moon icon for dark mode
99            }
100
101            // Toggle theme on button click
102            themeToggleButton.addEventListener("click", function() {
103                body.classList.toggle("dark-mode");
104                const isDarkMode = body.classList.contains("dark-mode");
105                themeToggleButton.textContent = isDarkMode ? "☀️" : "🌙"; // Toggle icons
106                localStorage.setItem("theme", isDarkMode ? "dark" : "light");
107            });
108        }
109
110        // Burger Menu Toggle Functionality
111        const toggleButton = document.querySelector('.pkp_site_nav_toggle');
112        const navMenu = document.querySelector('.pkp_navigation_primary_row');
113
114        // Add a click event to toggle menu visibility
115        if (toggleButton && navMenu) {
116            toggleButton.addEventListener('click', function() {
117                navMenu.classList.toggle('active');
118            });
119        }
120
121        // Copy to Clipboard Functionality
122        function enableCopyToClipboard() {
123            const copyElements = document.querySelectorAll("[data-copy-target]");
124
125            copyElements.forEach(element => {
126                const copyText = element.textContent || element.innerText;
127
128                element.style.cursor = "pointer"; // Indicate clickable
129                element.addEventListener("click", function() {
130                    navigator.clipboard.writeText(copyText).then(() => {
131                        alert("Copied to clipboard: " + copyText);
132                    }).catch((err) => {
133                        console.error("Failed to copy text: ", err);
134                    });
135                });
136            });
137        }
138
139        enableCopyToClipboard();
139 // Initialize copy-to-clipboard functionality on page load
140    });
141
142    document.addEventListener('DOMContentLoaded', function () {
143        function fetchTotalViews() {
144            const countElement = document.getElementById('count-all');
145            if (!countElement) {
146                console.log("count-all element not found on this page; skipping fetch.");
147                return;
148            }
149
150            fetch('/img/total_views.php')
151                .then(response => {
152                    if (!response.ok) throw new Error('Network response was not ok');
153                    return response.json();
154                })
155                .then(data => {
156                    countElement.innerText = data.totalViews;
157                    console.log("Updated count to:", data.totalViews);
158                })
159                .catch(error => {
160                    console.error('Error fetching total views:', error);
161                    const totalViewsContainer = document.getElementById('total-article-views');
162                    if (totalViewsContainer) {
163                        totalViewsContainer.innerHTML = '<h2>Error loading total views.</h2>';
164                    }
165                });
166        }
167
168        fetchTotalViews();
169    });
170
171    document.addEventListener('DOMContentLoaded', function () {
172        function fetchTotalComments() {
173            const countElement = document.getElementById('total-comments');
174            if (!countElement) {
175                console.log("total-comments element not found on this page; skipping fetch.");
176                return;
177            }
178
179            fetch('/img/total_comments.php')
180                .then(response => {
181                    if (!response.ok) throw new Error('Network response was not ok');
182                    return response.json();
183                })
184                .then(data => {
185                    countElement.innerText = data.totalComments;
186                    console.log("Updated total comments to:", data.totalComments);
187                })
188                .catch(error => {
189                    console.error('Error fetching total comments:', error);
190                    countElement.innerText = 'Error loading total comments.';
191                });
192        }
193
194        fetchTotalComments();
195    });
196
197    document.addEventListener("DOMContentLoaded", function() {
198        const searchToggleButton = document.getElementById("searchToggleButton");
199        const searchComponentContainer = document.querySelector(".search-component-container");
200        const searchForm = document.getElementById("searchForm");
201        const searchResults = document.getElementById("searchResults");
202
203        if (searchToggleButton && searchComponentContainer) {
204            searchToggleButton.addEventListener("click", function(event) {
205                event.stopPropagation();
206                searchComponentContainer.classList.toggle("show");
207            });
208
209            document.addEventListener("click", function(event) {
210                if (!searchComponentContainer.contains(event.target) && !searchToggleButton.contains(event.target)) {
211                    searchComponentContainer.classList.remove("show");
212                }
213            });
214        }
215
216        if (searchForm && searchResults) {
217            searchForm.addEventListener("submit", function(event) {
218                event.preventDefault();
219
220                const formData = new FormData(searchForm);
221                const query = (formData.get('query') || '').toString().trim();
222
223                if (query === "") {
224                    alert("Please enter a search query.");
225                    return;
226                }
227
228                searchResults.innerHTML = '<div class="spinner"></div>';
229                searchResults.style.display = "block";
230
231                const ajaxUrl = `https://mlhs.ink/Journal/index.php/Web3/search?${new URLSearchParams(formData).toString()}`;
232                console.log('AJAX URL:', ajaxUrl);
233
234                fetch(ajaxUrl, {
235                    method: "GET",
236                    headers: { 'X-Requested-With': 'XMLHttpRequest' },
237                    credentials: 'same-origin',
238                })
239                .then(response => {
240                    if (!response.ok) throw new Error("Network response was not ok");
241                    return response.text();
242                })
243                .then(data => {
244                    searchResults.innerHTML = data;
245                })
246                .catch(error => {
247                    console.error("Error fetching search results:", error);
248                    searchResults.innerHTML = `
249                        <p>An error occurred while fetching search results.</p>
250                        <button id="retrySearch">Retry</button>
251                    `;
252                    const btn = document.getElementById('retrySearch');
253                    if (btn) {
254                        btn.addEventListener('click', () => {
255                            searchForm.dispatchEvent(new Event('submit'));
256                        });
257                    }
258                });
259            });
260        }
261    });
262
263    document.addEventListener("DOMContentLoaded", function() {
264        const searchToggleButton = document.getElementById("searchToggleButton");
265        const searchComponentContainer = document.getElementById("searchComponentContainer");
266
267        if (searchToggleButton && searchComponentContainer) {
268            searchToggleButton.addEventListener("click", function() {
269                if (searchComponentContainer.style.display === "none" || searchComponentContainer.style.display === "") {
270                    searchComponentContainer.style.display = "block";
271                } else {
272                    searchComponentContainer.style.display = "none";
273                }
274            });
275        }
276    });
277
278})(jQuery);

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.