您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Creates a pop-up with Publisher, Country, Type, URL, and a custom-built visual quartile table for a perfect layout.
// ==UserScript== // @name Scimago Quartile Pop-up // @namespace http://tampermonkey.net/ // @version 1.1 // @description Creates a pop-up with Publisher, Country, Type, URL, and a custom-built visual quartile table for a perfect layout. // @author Gemini // @match https://www.scimagojr.com/journalsearch.php* // @grant GM_addStyle // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; window.addEventListener('load', () => { // --- 1. EXTRACT ALL REQUIRED INFO FROM THE PAGE --- const getInfoFromGrid = (headingText) => { const h2Elements = Array.from(document.querySelectorAll('.journalgrid h2')); const targetH2 = h2Elements.find(h2 => h2.textContent.trim() === headingText); if (targetH2) { return targetH2.nextElementSibling?.querySelector('a')?.textContent.trim() || targetH2.nextElementSibling.textContent.trim(); } return 'Not Found'; }; const journalTitle = document.querySelector('h1')?.innerText.trim() || 'Title Not Found'; const homepageLink = document.querySelector('a#question_journal[href*="http"]'); const publisher = getInfoFromGrid('Publisher'); const country = getInfoFromGrid('Country'); const publicationType = getInfoFromGrid('Publication type'); const originalDataTable = document.querySelector('#svgquartiles')?.parentElement.querySelector('.cellslide:nth-child(2) table'); if (!originalDataTable) { console.log("Scimago Pop-up: Quartile data not found."); return; } // --- 2. PARSE THE QUARTILE DATA --- const groupedData = {}; const years = new Set(); const rows = originalDataTable.querySelectorAll('tbody tr'); rows.forEach(row => { const cells = row.querySelectorAll('td'); if (cells.length !== 3) return; const category = cells[0].textContent.trim(); const year = cells[1].textContent.trim(); const quartile = cells[2].textContent.trim(); if (!groupedData[category]) groupedData[category] = {}; groupedData[category][year] = quartile; years.add(year); }); // *** CHANGE: Sort years and then reverse for newest-to-oldest order *** const sortedYears = Array.from(years).sort().reverse(); // --- 3. CREATE THE MODAL AND ITS HEADER --- const modalOverlay = document.createElement('div'); modalOverlay.id = 'info-modal-overlay'; const modalContainer = document.createElement('div'); modalContainer.id = 'info-modal-container'; const modalHeader = document.createElement('div'); modalHeader.id = 'info-modal-header'; const modalContent = document.createElement('div'); modalContent.id = 'info-modal-content'; const closeButton = document.createElement('span'); closeButton.id = 'info-modal-close'; closeButton.innerHTML = '×'; modalHeader.innerHTML = ` <h2>${journalTitle}</h2> <p><strong>Publisher:</strong> ${publisher}</p> <p><strong>Country:</strong> ${country}</p> <p><strong>Publication Type:</strong> ${publicationType}</p> ${homepageLink ? `<p><strong>Homepage:</strong> <a href="${homepageLink.href}" target="_blank" rel="noopener noreferrer">${homepageLink.href}</a></p>` : ''} `; // --- 4. BUILD THE NEW VISUAL TABLE FROM SCRATCH --- const visualTable = document.createElement('table'); visualTable.className = 'visual-quartile-table'; let headerHtml = '<thead><tr><th>Category</th>'; sortedYears.forEach(year => { headerHtml += `<th>${year}</th>`; }); // Header now uses reversed years headerHtml += '</tr></thead>'; visualTable.innerHTML = headerHtml; const tbody = document.createElement('tbody'); for (const category in groupedData) { const tr = document.createElement('tr'); let rowHtml = `<td>${category}</td>`; sortedYears.forEach(year => { // Data rows also use reversed years const quartile = groupedData[category][year] || ''; const quartileClass = quartile.toLowerCase(); rowHtml += `<td class="${quartileClass}">${quartile}</td>`; }); tr.innerHTML = rowHtml; tbody.appendChild(tr); } visualTable.appendChild(tbody); modalContent.appendChild(visualTable); // --- 5. ASSEMBLE, ADD FUNCTIONALITY, AND STYLE --- modalContainer.append(closeButton, modalHeader, modalContent); modalOverlay.appendChild(modalContainer); document.body.appendChild(modalOverlay); const closeModal = () => modalOverlay.remove(); closeButton.onclick = closeModal; modalOverlay.onclick = (e) => { if (e.target === modalOverlay) closeModal(); }; document.addEventListener('keydown', (e) => { if (e.key === "Escape") closeModal(); }); GM_addStyle(` #info-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.75); z-index: 10000; display: flex; justify-content: center; align-items: center; font-family: 'Roboto', sans-serif; /* --- CHANGE: Removed backdrop-filter for performance --- */ } #info-modal-container { background-color: #ffffff; padding: 0; border-radius: 12px; box-shadow: 0 10px 40px rgba(0,0,0,0.3); position: relative; max-width: 800px; width: 95%; max-height: 90vh; overflow: hidden; display: flex; flex-direction: column; animation: fadeIn 0.3s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } #info-modal-header { padding: 20px 30px; border-bottom: 1px solid #eee; flex-shrink: 0; } #info-modal-header h2 { margin: 0 0 12px 0; color: #2c3e50; font-size: 1.5em; } #info-modal-header p { margin: 5px 0 0 0; color: #333; line-height: 1.4; } #info-modal-header a { color: #e77642; text-decoration: none; word-break: break-all; } #info-modal-header a:hover { text-decoration: underline; } #info-modal-content { overflow: auto; padding: 25px 30px; } .visual-quartile-table { width: 100%; border-collapse: collapse; border: 1px solid #ccc; } .visual-quartile-table th, .visual-quartile-table td { border: 1px solid #ccc; padding: 12px; text-align: center; } .visual-quartile-table th { background-color: #f2f2f2; font-weight: bold; } .visual-quartile-table td:first-child { text-align: left; font-weight: 500; } .visual-quartile-table td.q1 { background-color: #a4cf63; color: white; } .visual-quartile-table td.q2 { background-color: #e8d559; color: #333; } .visual-quartile-table td.q3 { background-color: #fba353; color: white; } .visual-quartile-table td.q4 { background-color: #dd5a4e; color: white; } .visual-quartile-table td { font-weight: bold; font-size: 1.1em; } #info-modal-close { position: absolute; top: 15px; right: 20px; font-size: 35px; font-weight: bold; color: #aaa; cursor: pointer; transition: all 0.2s; z-index: 10; } #info-modal-close:hover { color: #2c3e50; transform: rotate(90deg); } `); }); })();