NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Cello Extract with One click Copy and Scrollable Table // @namespace http://tampermonkey.net/ // @version 5.1 // @description Display all rows with a star (*) on the second page in a scrollable table format. Copy functionality ensures data from the Short Form column is pasted into a single Excel cell per index. Scan the entire page for Gene Name after SeqID:, and place each Gene Name in its respective row, adding ">" before each Gene Name without space. Adds notification on successful copy and fixed title on the table. // @author Faisal Ahmed // @license MIT // @match http://cello.life.nctu.edu.tw/ // @match http://cello.life.nctu.edu.tw/cgi/main.cgi // @grant none // ==/UserScript== (function () { 'use strict'; // Function to show a brief notification for 1 second function showNotification(message) { let notification = document.createElement('div'); notification.innerText = message; notification.style.position = 'fixed'; notification.style.top = '50px'; notification.style.right = '10px'; notification.style.backgroundColor = 'green'; notification.style.color = 'white'; notification.style.padding = '10px'; notification.style.borderRadius = '5px'; notification.style.zIndex = '9999'; document.body.appendChild(notification); // Remove the notification after 1 second setTimeout(() => { notification.remove(); }, 1000); } // Mapping of full forms to short forms with Unicode superscript "a" const fullToShortForm = { "Extracellular": "Exᵃ", "Cytoplasmic": "Cyᵃ", "Lysosomal": "Lyᵃ", "Vacuole": "Vᵃ", "Chloroplast": "Chᵃ", "Nuclear": "Nuᵃ", "Golgi": "Gᵃ", "ER": "ERᵃ", "Mitochondrial": "Mᵃ", "InnerMembrane": "IMᵃ", "OuterMembrane": "OMᵃ", "Periplasmic": "Periᵃ", "PlasmaMembrane": "Pmᵃ" }; // Function to scan the entire page and extract all Gene Names after "SeqID:" function extractAllGeneNames() { let pageText = document.body.innerText.split('\n'); // Split the entire page text into lines console.log("Page text for scanning Gene Names:", pageText); let geneNames = []; // Look for all lines that contain "SeqID:" and extract the gene names for (let line of pageText) { if (line.includes("SeqID:")) { let geneName = line.split("SeqID:")[1].split("|")[0].trim(); // Extract Gene Name after SeqID: and before | console.log("Extracted Gene Name:", geneName); geneNames.push(geneName); // Store each extracted Gene Name } } return geneNames; // Return the list of all extracted Gene Names } function handleSecondPage() { let geneNames = extractAllGeneNames(); // Extract all Gene Names from the page let lines = document.body.innerText.split('\n'); // Split the page text into individual lines let sequences = []; // Array to store sequences let currentSequence = []; // Store the current sequence being processed // Search for all lines, grouping them by sequence (assuming empty lines separate sequences) lines.forEach((line) => { if (line.trim() === "") { if (currentSequence.length > 0) { sequences.push(currentSequence); // Push current sequence to the sequences array currentSequence = []; // Reset current sequence } } else { currentSequence.push(line.trim()); // Add line to current sequence } }); // Handle last sequence if not empty if (currentSequence.length > 0) { sequences.push(currentSequence); } // Prepare data with star (*) containing lines for each sequence let sequenceData = sequences.map((sequence) => { return sequence.filter(line => { let starCount = (line.match(/\*/g) || []).length; // Count the number of * symbols in the line return starCount > 0 && starCount <= 3; // Include lines with 1 to 3 stars only }); }).filter(data => data.length > 0); // Keep only sequences with star-containing lines if (sequenceData.length > 0) { // Create a scrollable table element let tableContainer = document.createElement('div'); tableContainer.style.position = 'fixed'; tableContainer.style.top = '10px'; tableContainer.style.right = '10px'; tableContainer.style.width = '400px'; tableContainer.style.height = '300px'; // Limit the table height to 300px tableContainer.style.overflowY = 'auto'; // Add vertical scrolling tableContainer.style.border = '1px solid #ccc'; // Softer border color tableContainer.style.backgroundColor = '#B0B0B0'; // Ash background color tableContainer.style.borderRadius = '10px'; // Rounded corners tableContainer.style.boxShadow = '0px 4px 12px rgba(0, 0, 0, 0.1)'; // Subtle shadow for depth tableContainer.style.zIndex = '9999'; tableContainer.style.transition = 'all 0.3s ease'; // Smooth transition for interactions // Create the title element with rainbow animation let title = document.createElement('div'); title.innerText = 'Made By Faisal Ahmed'; title.style.position = 'sticky'; title.style.top = '0'; title.style.backgroundImage = 'linear-gradient(90deg, red, orange, yellow, green, blue, indigo, violet)'; title.style.backgroundSize = '200%'; // Make the gradient larger for movement title.style.backgroundClip = 'text'; // Apply gradient only to text title.style.color = 'transparent'; // Hide the background title.style.textAlign = 'center'; title.style.padding = '5px'; title.style.fontWeight = 'bold'; title.style.zIndex = '1000'; // Ensure it stays on top title.style.borderBottom = '1px solid #ccc'; // Add the animation to the title title.style.animation = 'rainbowAnimation 5s linear infinite'; // Slower and right-to-left animation // Append the title to the table container tableContainer.appendChild(title); // Create the table inside the scrollable container let table = document.createElement('table'); table.style.width = '100%'; // Make the table take up full width of the container // Create table headers with copy buttons let headerRow = document.createElement('tr'); let th1 = document.createElement('th'); let th2 = document.createElement('th'); let th3 = document.createElement('th'); // Create Copy Buttons for each column let copyGeneNameButton = document.createElement('button'); copyGeneNameButton.innerText = 'Copy Gene Name'; copyGeneNameButton.style.margin = '5px'; copyGeneNameButton.addEventListener('click', function () { copyColumnData(0); // Copy the first column (Gene Name) }); let copyShortFormButton = document.createElement('button'); copyShortFormButton.innerText = 'Copy Short Form'; copyShortFormButton.style.margin = '5px'; copyShortFormButton.addEventListener('click', function () { copyColumnData(1); // Copy the second column (Short Form) }); let copyDataButton = document.createElement('button'); copyDataButton.innerText = 'Copy Data'; copyDataButton.style.margin = '5px'; copyDataButton.addEventListener('click', function () { copyColumnData(2); // Copy the third column (Data) }); th1.appendChild(copyGeneNameButton); th2.appendChild(copyShortFormButton); th3.appendChild(copyDataButton); headerRow.appendChild(th1); headerRow.appendChild(th2); headerRow.appendChild(th3); table.appendChild(headerRow); // Populate the table with sequence-related star data sequenceData.forEach((data, index) => { let row = document.createElement('tr'); let geneNameCell = document.createElement('td'); // Assign each gene name to the respective row (1st gene name -> 1st row, 2nd gene name -> 2nd row) let geneName = geneNames[index] || 'N/A'; // Handle cases where there are fewer gene names than rows geneNameCell.innerText = `>${geneName}`; // Add ">" directly before the Gene Name without any space geneNameCell.style.border = '1px solid black'; let shortFormCell = document.createElement('td'); shortFormCell.innerText = generateShortForm(data); // Create the correct short form for each line in the sequence shortFormCell.style.border = '1px solid black'; let dataCell = document.createElement('td'); dataCell.innerText = data.join('\n'); // Join multiple lines into a single cell dataCell.style.border = '1px solid black'; row.appendChild(geneNameCell); // Append Gene Name to the first column row.appendChild(shortFormCell); row.appendChild(dataCell); table.appendChild(row); }); // Append the table to the container tableContainer.appendChild(table); // Append the container to the body document.body.appendChild(tableContainer); // Function to copy column data to the clipboard function copyColumnData(columnIndex) { let tableRows = table.querySelectorAll('tr'); let columnData = Array.from(tableRows).slice(1) // Skip the header row .map(row => row.cells[columnIndex].innerText.replace(/\n/g, ' ')) // Replace newlines with spaces for Excel single-cell entries .join('\n'); // Create a temporary textarea element to copy the content let tempTextarea = document.createElement('textarea'); tempTextarea.value = columnData; document.body.appendChild(tempTextarea); tempTextarea.select(); document.execCommand('copy'); document.body.removeChild(tempTextarea); // Show a brief notification when copied showNotification(`${['Gene Name', 'Short Form', 'Data'][columnIndex]} column copied!`); } // Function to generate a short form using Unicode superscript "a" for each line in the sequence function generateShortForm(sequence) { return sequence.map(line => { let fullForm = Object.keys(fullToShortForm).find(form => line.includes(form)); if (fullForm) { return fullToShortForm[fullForm]; // Return the short form with Unicode superscript } return ''; // If no match is found, return an empty string }).join(', '); // Join multiple entries with commas to keep them in a single Excel cell } } else { console.log("No lines with a valid number of stars (*) found."); } } // Handle the second page handleSecondPage(); // CSS for rainbow animation const style = document.createElement('style'); style.innerHTML = ` @keyframes rainbowAnimation { 0% { background-position: 200%; } 100% { background-position: 0%; } } `; document.head.appendChild(style); })();