NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Expasy Data Extract (Auto Submit, Excel Table) // @namespace http://tampermonkey.net/ // @version 2.2 // @description Collect specific protein data from Expasy ProtParam results, display it in an elegant table with copy functionality and notification, and include a fixed title. Molecular weight is divided by 1000 before displaying. // @author Faisal Ahmed // @license MIT // @match https://web.expasy.org/protparam/* // @match https://web.expasy.org/cgi-bin/protparam/protparam* // @grant none // ==/UserScript== (function() { 'use strict'; // Log messages to help debugging console.log("Tampermonkey script started!"); // Function to create and show the table for displaying collected data function createExcelTable(proteinData) { console.log("Creating Excel-like table..."); // Create a container div for the table const tableContainer = document.createElement('div'); tableContainer.style.position = 'fixed'; tableContainer.style.top = '10px'; tableContainer.style.right = '10px'; tableContainer.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'; tableContainer.style.color = '#000'; tableContainer.style.padding = '15px'; tableContainer.style.borderRadius = '8px'; tableContainer.style.zIndex = '9999'; tableContainer.style.width = '450px'; tableContainer.style.fontSize = '12px'; // Smaller font size tableContainer.style.maxHeight = '400px'; tableContainer.style.overflowY = 'auto'; tableContainer.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; // Create and style the fixed title with blinking rainbow effect const fixedTitle = document.createElement('div'); fixedTitle.textContent = 'Made By Faisal Ahmed'; fixedTitle.style.fontSize = '14px'; // Slightly smaller title font fixedTitle.style.fontWeight = 'bold'; fixedTitle.style.marginBottom = '10px'; fixedTitle.style.paddingBottom = '5px'; fixedTitle.style.borderBottom = '1px solid #ddd'; fixedTitle.style.textAlign = 'center'; fixedTitle.style.backgroundClip = 'text'; fixedTitle.style.webkitBackgroundClip = 'text'; // For Safari and Chrome fixedTitle.style.color = 'transparent'; // Hide the original text color fixedTitle.style.backgroundImage = 'linear-gradient(to right, violet, indigo, blue, green, yellow, orange, red)'; fixedTitle.style.animation = 'blink 5s linear infinite'; // Add CSS for the blinking rainbow effect const style = document.createElement('style'); style.innerHTML = ` @keyframes blink { 0% { background-position: 100%; } 50% { background-position: 0%; } 100% { background-position: 100%; } } div { background-size: 200%; } `; document.head.appendChild(style); tableContainer.appendChild(fixedTitle); // Create a table element const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; table.style.textAlign = 'left'; table.style.backgroundColor = '#333'; // Darker background color for the table table.style.borderRadius = '8px'; // Rounded corners for the table table.style.fontSize = '12px'; // Smaller font size for table // Create the table header const headerRow = document.createElement('tr'); const headers = ['Protein Length (aa)', 'Molecular weight (kDa)', 'Theoretical pI', 'Instability index', 'Aliphatic index', 'GRAVY']; headers.forEach(headerText => { const th = document.createElement('th'); th.textContent = headerText; th.style.border = '1px solid #444'; // Darker border for header th.style.padding = '10px'; // Reduced padding for a more compact look th.style.backgroundColor = '#555'; // Slightly lighter dark color for header th.style.color = '#fff'; // White text for better contrast th.style.borderRadius = '4px'; th.style.fontWeight = 'bold'; headerRow.appendChild(th); }); table.appendChild(headerRow); // Create the table row with protein data const dataRow = document.createElement('tr'); for (const key in proteinData) { const td = document.createElement('td'); // Add condition for the "Instability index" column if (key === "Instability index") { const instabilityValue = parseFloat(proteinData[key]); if (!isNaN(instabilityValue)) { if (instabilityValue > 39.9) { td.textContent = `${instabilityValue} (unstable)`; } else { td.textContent = `${instabilityValue} (stable)`; } } else { td.textContent = "Nope"; } } else if (key === "Molecular weight") { // Divide molecular weight by 1000 and show in kDa const molecularWeightValue = parseFloat(proteinData[key]); td.textContent = !isNaN(molecularWeightValue) ? `${(molecularWeightValue / 1000).toFixed(3)}` : 'Nope'; } else { td.textContent = proteinData[key] || 'Nope'; } td.style.border = '1px solid #444'; // Darker border for data cells td.style.padding = '8px'; // Reduced padding for a more compact look td.style.borderRadius = '4px'; td.style.color = '#fff'; // White text for better contrast dataRow.appendChild(td); } table.appendChild(dataRow); // Create the "Copy" button const copyButton = document.createElement('button'); copyButton.textContent = 'Copy Data'; copyButton.style.marginTop = '15px'; copyButton.style.padding = '8px 15px'; copyButton.style.backgroundColor = '#007bff'; copyButton.style.color = '#fff'; copyButton.style.border = 'none'; copyButton.style.borderRadius = '5px'; copyButton.style.cursor = 'pointer'; copyButton.style.fontSize = '12px'; // Smaller font size for the button copyButton.addEventListener('click', copyTableData); tableContainer.appendChild(copyButton); // Append the table to the container tableContainer.appendChild(table); // Add the table container to the webpage document.body.appendChild(tableContainer); console.log("Excel-like table created and data added."); } // Function to extract data from the plain text result function extractProteinDataFromText() { let proteinData = {}; // Get the entire text content of the page const resultText = document.body.textContent; console.log("Result text found on the page."); // Use regular expressions to extract the specific data points const aminoAcidsMatch = resultText.match(/Number of amino acids:\s*(\d+)/); const molecularWeightMatch = resultText.match(/Molecular weight:\s*([\d.]+)/); const piMatch = resultText.match(/Theoretical pI:\s*([\d.]+)/); const instabilityIndexMatch = resultText.match(/The instability index \(II\) is computed to be\s*([\d.]+)/); const aliphaticIndexMatch = resultText.match(/Aliphatic index:\s*([\d.]+)/); const gravyMatch = resultText.match(/Grand average of hydropathicity \(GRAVY\):\s*([\d.-]+)/); // Save the matched results in the proteinData object proteinData["Number of amino acids"] = aminoAcidsMatch ? aminoAcidsMatch[1] : "Nope"; proteinData["Molecular weight"] = molecularWeightMatch ? molecularWeightMatch[1] : "Nope"; proteinData["Theoretical pI"] = piMatch ? piMatch[1] : "Nope"; proteinData["Instability index"] = instabilityIndexMatch ? instabilityIndexMatch[1] : "Nope"; proteinData["Aliphatic index"] = aliphaticIndexMatch ? aliphaticIndexMatch[1] : "Nope"; proteinData["GRAVY"] = gravyMatch ? gravyMatch[1] : "Nope"; console.log("Protein data extracted:", proteinData); // Create and display the table with the extracted data createExcelTable(proteinData); } // On the form page (https://web.expasy.org/protparam/), listen for paste event and submit the form automatically if (window.location.href.includes("web.expasy.org/protparam/")) { const sequenceInput = document.querySelector('textarea'); const form = document.querySelector('form'); if (sequenceInput && form) { console.log("Form detected on the protparam page."); // Listen for paste event in the sequence input sequenceInput.addEventListener('paste', function(event) { setTimeout(function() { if (sequenceInput.value.trim().length > 0) { // Create a form data object const formData = new FormData(form); // Construct the URL for the new tab with form data as query params const urlParams = new URLSearchParams(formData).toString(); const targetURL = `${form.action}?${urlParams}`; // Open the new tab with the constructed URL console.log("Opening results in a new tab..."); window.open(targetURL, '_blank'); // Reset the form in the original tab console.log("Resetting the form in the original tab..."); form.reset(); } }, 100); // Delay to ensure paste is completed }); } } // Function to display a temporary notification function showCopyNotification() { const notification = document.createElement('div'); notification.textContent = 'Table data copied to clipboard!'; notification.style.position = 'fixed'; notification.style.top = '20px'; // Changed from bottom to top notification.style.right = '20px'; notification.style.backgroundColor = '#28a745'; notification.style.color = '#fff'; notification.style.padding = '10px 20px'; notification.style.borderRadius = '5px'; notification.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; notification.style.zIndex = '9999'; document.body.appendChild(notification); // Remove notification after 1 second setTimeout(() => { notification.remove(); }, 1000); } // Function to copy the table data to the clipboard function copyTableData() { const table = document.querySelector('table'); // Create a temporary textarea to store table data for copying const tempTextArea = document.createElement('textarea'); tempTextArea.style.position = 'fixed'; // Prevent it from appearing in the view tempTextArea.style.opacity = '0'; document.body.appendChild(tempTextArea); // Collect data from each table cell, excluding the title row let tableData = ''; table.querySelectorAll('tr').forEach((row, rowIndex) => { if (rowIndex > 0) { // Skip the header row (rowIndex 0) row.querySelectorAll('td').forEach(cell => { tableData += cell.textContent.trim() + '\t'; // Tab-separated values }); tableData += '\n'; // New line for each row } }); // Set the collected table data into the textarea tempTextArea.value = tableData; tempTextArea.select(); document.execCommand('copy'); document.body.removeChild(tempTextArea); // Remove the temporary textarea // Show the copy notification showCopyNotification(); } // Wait for the page to load and then extract the data window.addEventListener('load', extractProteinDataFromText); })();