PageSourceSearch

https://esr.ie/plugins/generic/articleStatisticsDisplay/js/main.js?v=3.3.0.20

js esr.ie collected 2026-10-02 03:44:18 UTC 10,658 bytes, 285 lines download raw bytes

1/**
2 * Article Statistics Display Plugin - Main JavaScript
3 * 
4 * Copyright (c) 2026 Kerim Sarıgül
5 * Distributed under the GNU GPL v3.
6 *
7 * Positions stats in three locations:
8 * 1. Under title (horizontal)
9 * 2. Under abstract (horizontal)
10 * 3. Article sidebar (vertical - each stat on its own line)
11 * 
12 * Also handles summary view: moves stats next to galley buttons
13 */
14
15(function() {
16    'use strict';
17
18    document.addEventListener('DOMContentLoaded', function() {
19        var settings = window.asdSettings || { position: 'underTitle', style: 'badge' };
20        
21        // Handle article detail page
22        positionStats(settings.position);
23        
24        // Handle summary/list views - move stats next to galley buttons
25        moveSummaryStatsToGalleys();
26    });
27
28    /**
29     * Move summary stats next to galley buttons in list views
30     * Handles different theme structures intelligently
31     */
32    function moveSummaryStatsToGalleys() {
33        var summaryStats = document.querySelectorAll('.asd-stats-summary');
34        
35        summaryStats.forEach(function(statsEl) {
36            // Find the parent article container - expanded selectors for more themes
37            var articleContainer = statsEl.closest('.obj_article_summary, .article_summary, .article-summary, article, .media, .card, .article-item');
38            if (!articleContainer) {
39                articleContainer = statsEl.parentElement;
40            }
41            
42            if (!articleContainer) {
43                statsEl.classList.add('asd-moved');
44                return;
45            }
46            
47            // Strategy 1: Find galleys_links ul (Default/Manuscript theme)
48            var galleysUl = articleContainer.querySelector('ul.galleys_links, .galleys_links');
49            if (galleysUl && galleysUl.tagName === 'UL') {
50                var li = document.createElement('li');
51                li.style.display = 'inline';
52                li.appendChild(statsEl);
53                galleysUl.appendChild(li);
54                statsEl.classList.add('asd-moved');
55                return;
56            }
57            
58            // Strategy 2: Find btn-group (Bootstrap theme)
59            var btnGroup = articleContainer.querySelector('.btn-group');
60            if (btnGroup) {
61                // Insert after btn-group, not inside
62                if (btnGroup.nextSibling) {
63                    btnGroup.parentNode.insertBefore(statsEl, btnGroup.nextSibling);
64                } else {
65                    btnGroup.parentNode.appendChild(statsEl);
66                }
67                statsEl.style.marginLeft = '8px';
68                statsEl.classList.add('asd-moved');
69                return;
70            }
71            
72            // Strategy 3: Find article-summary-galleys (Health Science theme)
73            var healthScienceGalleys = articleContainer.querySelector('.article-summary-galleys');
74            if (healthScienceGalleys) {
75                healthScienceGalleys.appendChild(statsEl);
76                statsEl.style.marginLeft = '8px';
77                statsEl.style.display = 'inline-block';
78                statsEl.classList.add('asd-moved');
79                return;
80            }
81            
82            // Strategy 4: Find other galley containers
83            var galleyContainers = articleContainer.querySelectorAll('.galleys, .galley-links, .galley_links, .entry_details .galleys, .download-links');
84            if (galleyContainers.length > 0) {
85                var container = galleyContainers[0];
86                container.appendChild(statsEl);
87                statsEl.style.marginLeft = '8px';
88                statsEl.classList.add('asd-moved');
89                return;
90            }
91            
92            // Strategy 5: Find last galley link and insert after
93            var galleyLinks = articleContainer.querySelectorAll('.obj_galley_link, a.galley-link, a.galley_link, .btn.galley-link, a[href*="/article/view/"][href*="/galley/"], a[href*="view"][class*="galley"]');
94            if (galleyLinks.length > 0) {
95                var lastGalley = galleyLinks[galleyLinks.length - 1];
96                var parent = lastGalley.parentElement;
97                
98                // If parent is li, go up one more level
99                if (parent.tagName === 'LI') {
100                    parent = parent.parentElement;
101                }
102                
103                // Insert after the last galley or its container
104                if (lastGalley.nextSibling) {
105                    lastGalley.parentNode.insertBefore(statsEl, lastGalley.nextSibling);
106                } else {
107                    lastGalley.parentNode.appendChild(statsEl);
108                }
109                statsEl.style.marginLeft = '8px';
110                statsEl.classList.add('asd-moved');
111                return;
112            }
113            
114            // Fallback: just show in place
115            statsEl.classList.add('asd-moved');
116        });
117    }
118
119    /**
120     * Position stats based on selected option (for detail page)
121     */
122    function positionStats(position) {
123        var statsContainer = document.querySelector('.asd-stats-detail');
124        if (!statsContainer) return;
125        
126        var articlePage = document.querySelector('.obj_article_details, .article-details, .article_details');
127        if (!articlePage) return;
128        
129        var targetElement = null;
130        
131        switch (position) {
132            case 'underTitle':
133                targetElement = findTitleElement(articlePage);
134                if (targetElement) {
135                    targetElement.parentNode.insertBefore(statsContainer, targetElement.nextSibling);
136                    statsContainer.style.marginTop = '15px';
137                    statsContainer.style.marginBottom = '20px';
138                    statsContainer.classList.remove('asd-vertical');
139                }
140                break;
141                
142            case 'underAbstract':
143                targetElement = findAbstractElement(articlePage);
144                if (targetElement) {
145                    targetElement.parentNode.insertBefore(statsContainer, targetElement.nextSibling);
146                    statsContainer.style.marginTop = '20px';
147                    statsContainer.classList.remove('asd-vertical');
148                }
149                break;
150                
151            case 'sidebar':
152                var sidebar = findSidebarElement(articlePage);
153                if (sidebar) {
154                    // Add vertical class for sidebar display
155                    statsContainer.classList.add('asd-vertical');
156                    
157                    // Create a wrapper for sidebar
158                    var wrapper = document.createElement('div');
159                    wrapper.className = 'item asd-sidebar-item';
160                    wrapper.appendChild(statsContainer);
161                    
162                    // Try to find galley element to insert after
163                    var galleyEl = findGalleyInSidebar(sidebar);
164                    if (galleyEl) {
165                        // Insert after galley
166                        if (galleyEl.nextSibling) {
167                            galleyEl.parentNode.insertBefore(wrapper, galleyEl.nextSibling);
168                        } else {
169                            galleyEl.parentNode.appendChild(wrapper);
170                        }
171                    } else {
172                        // Fallback: insert at beginning
173                        var firstItem = sidebar.querySelector('.item, .block');
174                        if (firstItem) {
175                            sidebar.insertBefore(wrapper, firstItem);
176                        } else {
177                            sidebar.insertBefore(wrapper, sidebar.firstChild);
178                        }
179                    }
180                }
181                break;
182        }
183    }
184
185    /**
186     * Find title element
187     */
188    function findTitleElement(articlePage) {
189        var selectors = [
190            '.obj_article_details .page_title',
191            '.article-details h1',
192            'h1.page_title',
193            '.page_title'
194        ];
195        
196        for (var i = 0; i < selectors.length; i++) {
197            var el = document.querySelector(selectors[i]);
198            if (el) return el;
199        }
200        
201        return articlePage.querySelector('h1, .title');
202    }
203
204    /**
205     * Find abstract element
206     */
207    function findAbstractElement(articlePage) {
208        var selectors = [
209            '.obj_article_details .abstract',
210            '.article-details .abstract',
211            '.item.abstract',
212            'section.abstract',
213            '.abstract'
214        ];
215        
216        for (var i = 0; i < selectors.length; i++) {
217            var el = document.querySelector(selectors[i]);
218            if (el) return el;
219        }
220        
221        return null;
222    }
223
224    /**
225     * Find sidebar element and insert after galleys
226     */
227    function findSidebarElement(articlePage) {
228        var selectors = [
229            '.article_sidebar',
230            '.article-sidebar',
231            '.sidebar',
232            '.obj_article_details .entry_details',
233            '.entry_details',
234            '.article-details aside',
235            'aside.sidebar',
236            '.col-md-4',  // Bootstrap sidebar column
237            '.pkp_structure_sidebar'
238        ];
239        
240        var sidebar = null;
241        for (var i = 0; i < selectors.length; i++) {
242            var el = document.querySelector(selectors[i]);
243            if (el) {
244                sidebar = el;
245                break;
246            }
247        }
248        
249        if (!sidebar) {
250            // Fallback: try to find sidebar by structure
251            var mainContent = document.querySelector('.obj_article_details .main_entry, .article-details .main');
252            if (mainContent && mainContent.nextElementSibling) {
253                sidebar = mainContent.nextElementSibling;
254            }
255        }
256        
257        return sidebar;
258    }
259    
260    /**
261     * Find galley element in sidebar to insert after
262     */
263    function findGalleyInSidebar(sidebar) {
264        var galleySelectors = [
265            '.item.galleys',
266            '.galleys',
267            '.galley-links',
268            '.download'
269        ];
270        
271        for (var i = 0; i < galleySelectors.length; i++) {
272            var el = sidebar.querySelector(galleySelectors[i]);
273            if (el) return el;
274        }
275        
276        // Try to find by PDF link
277        var pdfLink = sidebar.querySelector('a[href*="/galley/"], .obj_galley_link');
278        if (pdfLink) {
279            return pdfLink.closest('.item') || pdfLink.parentElement;
280        }
281        
282        return null;
283    }
284
285})();

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.