您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds copy button and double-click functionality to extract formatted text from scholarqa.allen.ai
- // ==UserScript==
- // @name ScholarQA Enhanced Copy Tools
- // @namespace https://violentmonkey.github.io/
- // @version 1.4
- // @description Adds copy button and double-click functionality to extract formatted text from scholarqa.allen.ai
- // @author Bui Quoc Dung
- // @match *://scholarqa.allen.ai/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- // Define CSS selector variables for easier maintenance
- const ACCORDION_SUMMARY_SELECTOR = '.MuiButtonBase-root.MuiAccordionSummary-root';
- const ACCORDION_ROOT_SELECTOR = '.MuiAccordion-root';
- const ACCORDION_HEADING_SELECTOR = '.MuiTypography-h5';
- const ACCORDION_BODY_SELECTOR = '.MuiTypography-body1';
- const CITATION_SELECTOR = '.MuiChip-root';
- const PARAGRAPH_SELECTOR = '.MuiCollapse-root';
- const COPY_BUTTON_CLASS = 'MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall';
- // Find the "Disclaimer" button dynamically based on its text content
- function findDisclaimerButton() {
- const buttons = document.querySelectorAll('button');
- for (let button of buttons) {
- if (button.textContent.includes('Disclaimer')) {
- return button;
- }
- }
- return null;
- }
- // Expands all collapsed sections for complete content extraction
- function expandSections() {
- console.log("Expanding all sections...");
- document.querySelectorAll(ACCORDION_SUMMARY_SELECTOR).forEach(btn => btn.click());
- }
- // Shows notification when content is copied
- function showNotification(x, y) {
- let notification = document.createElement('div');
- notification.innerText = "Copied!";
- Object.assign(notification.style, {
- position: 'absolute',
- left: `${x}px`,
- top: `${y}px`,
- background: 'rgba(0, 0, 0, 0.8)',
- color: 'white',
- padding: '8px 12px',
- borderRadius: '5px',
- fontSize: '14px',
- zIndex: '1000',
- transition: 'opacity 0.5s'
- });
- document.body.appendChild(notification);
- setTimeout(() => {
- notification.style.opacity = '0';
- setTimeout(() => document.body.removeChild(notification), 500);
- }, 1500);
- }
- // Copies formatted HTML content to clipboard
- function copyToClipboard(text) {
- let tempContainer = document.createElement('div');
- tempContainer.innerHTML = text;
- document.body.appendChild(tempContainer);
- let range = document.createRange();
- range.selectNode(tempContainer);
- let selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(range);
- try {
- document.execCommand('copy');
- console.log("Copied formatted text.");
- } catch (err) {
- console.error("Copy failed", err);
- }
- selection.removeAllRanges();
- document.body.removeChild(tempContainer);
- }
- // Processes text from a single paragraph element
- function processText(paragraphElement, includeHeading = true) {
- let tempDiv = paragraphElement.cloneNode(true);
- let paragraphText = tempDiv.innerHTML;
- tempDiv.querySelectorAll(CITATION_SELECTOR).forEach(citation => {
- let linkElement = citation.closest('a');
- if (linkElement) {
- let hyperlink = linkElement.href;
- let citationText = citation.innerText;
- let formattedCitation = `<a href="${hyperlink}" target="_blank">${citationText}</a>`;
- paragraphText = paragraphText.replace(citation.outerHTML, formattedCitation);
- }
- });
- paragraphText = paragraphText.replace(/<div[^>]*>/g, ' ')
- .replace(/<\/div>/g, '')
- .replace(/\s+/g, ' ');
- paragraphText = paragraphText.replace(/Is this section helpful\? /g, ""); // Remove "Is this section helpful? "
- if (includeHeading) {
- let headingText = "";
- let intermediateText = "";
- let accordion = paragraphElement.closest(ACCORDION_ROOT_SELECTOR);
- if (accordion) {
- let headingElement = accordion.querySelector(ACCORDION_HEADING_SELECTOR);
- if (headingElement) {
- headingText = `<strong><u>${headingElement.innerText.trim()}</u></strong>`.trim();
- }
- let intermediateElement = accordion.querySelector(ACCORDION_BODY_SELECTOR);
- if (intermediateElement) {
- intermediateText = intermediateElement.innerText.trim();
- }
- if (headingText) {
- let prefix = headingText + ':\n';
- if (intermediateText) {
- prefix += intermediateText + '\n';
- }
- paragraphText = prefix + paragraphText;
- }
- }
- }
- return paragraphText;
- }
- // Adds a copy button next to the "Disclaimer" button
- function addCopyButton() {
- let targetButton = findDisclaimerButton();
- if (!targetButton) {
- return;
- }
- if (document.querySelector('#custom-copy-button')) {
- return;
- }
- let copyButton = document.createElement('button');
- copyButton.id = 'custom-copy-button';
- copyButton.className = COPY_BUTTON_CLASS;
- copyButton.style.marginLeft = '10px';
- copyButton.style.color = 'black';
- copyButton.title = "Copy Text";
- copyButton.textContent = "Copy";
- targetButton.parentNode.insertBefore(copyButton, targetButton.nextSibling);
- copyButton.addEventListener('click', (event) => {
- console.log("Copy button clicked!");
- copyButton.textContent = "Coping";
- expandSections();
- setTimeout(() => {
- let copiedText = extractAllText();
- copyToClipboard(copiedText);
- copyButton.textContent = "Copy";
- }, 1500);
- });
- }
- // Extracts formatted text from all paragraphs
- function extractAllText() {
- let paragraphs = document.querySelectorAll(PARAGRAPH_SELECTOR);
- let copiedText = "";
- paragraphs = Array.from(paragraphs).slice(0, -1); // Loại bỏ phần tử cuối
- paragraphs.forEach(paragraph => {
- let processedText = processText(paragraph, true);
- copiedText += processedText + '\n\n';
- });
- return copiedText;
- }
- // Handles double-click event to copy individual paragraph
- function handleDoubleClick(event) {
- const targetDiv = event.target.closest(PARAGRAPH_SELECTOR);
- if (!targetDiv) return;
- let accordion = targetDiv.closest(ACCORDION_ROOT_SELECTOR);
- if (accordion) {
- let button = accordion.querySelector(ACCORDION_SUMMARY_SELECTOR);
- if (button) {
- button.click();
- }
- }
- setTimeout(() => {
- let textContent = processText(targetDiv, true);
- copyToClipboard(textContent);
- showNotification(event.pageX, event.pageY);
- }, 500);
- }
- // Initialize both features
- function initialize() {
- const observer = new MutationObserver(() => {
- addCopyButton();
- });
- observer.observe(document.body, { childList: true, subtree: true });
- document.body.addEventListener('dblclick', handleDoubleClick);
- setTimeout(addCopyButton, 2000);
- }
- initialize();
- })();