LaTeX Copier

Copy selected text from wiki with equations in LaTeX format

目前为 2024-11-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name LaTeX Copier
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.7
  5. // @description Copy selected text from wiki with equations in LaTeX format
  6. // @author Jie-Qiao
  7. // @match *://*.wikipedia.org/*
  8. // @match *://*.stackexchange.com/*
  9. // @match *://alejandroschuler.github.io/*
  10. // @match *://*.zhihu.com/*
  11. // @match *://ar5iv.labs.arxiv.org/*
  12. // @match *://*.csdn.net/*
  13. // @grant none
  14. // @license MIT
  15. // ==/UserScript==
  16.  
  17. function getTextContentWithReplacements(url,node) {
  18. let text = '';
  19. if (node && node.childNodes) {
  20. node.childNodes.forEach(child => {
  21. const nodeType = child.nodeType;
  22. const nodeName = child.nodeName.toLowerCase();
  23. // Default behavior for text nodes
  24. if (child.nodeType === Node.TEXT_NODE) {
  25. text += child.textContent;
  26. }
  27. if (nodeType === Node.ELEMENT_NODE){
  28. // URL-specific processing rules
  29. if (url.includes('wikipedia.org')) {
  30. if (nodeName === 'span') {
  31. if (child.querySelectorAll('math').length > 0) {
  32. text += '$' + child.getElementsByTagName('math')[0].getAttribute('alttext') + '$';
  33. } else if (child.querySelectorAll('img').length > 0) {
  34. text += '$' + child.querySelectorAll('img')[0].getAttribute('alt') + '$';
  35. }
  36. }
  37. } else if (url.includes('stackexchange.com') || url.includes('zhihu.com')) {
  38. if (nodeName === 'span') {
  39. if (child.getElementsByTagName('script').length > 0) {
  40. text += '$' + child.getElementsByTagName('script')[0].textContent + '$';
  41. }
  42. }
  43. if (nodeName === 'script') {
  44. text += '$' + child.textContent + '$';
  45. }
  46. } else if (url.includes('alejandroschuler.github.io')) {
  47. if (nodeName === 'span') {
  48. if (child.getElementsByTagName('annotation').length > 0) {
  49. text += '$' + child.getElementsByTagName('annotation')[0].textContent + '$';
  50. }
  51. }
  52. } else if (url.includes('ar5iv.labs.arxiv.org')){
  53. if (nodeName === 'math'){
  54. text += '$' + child.getAttribute('alttext') + '$'
  55. }
  56. } else if (url.includes('csdn.net')){
  57. if (nodeName === 'span' && (child.getAttribute('class')==="katex--display" || child.getAttribute('class')==="katex--inline")){
  58. const temp=child.getElementsByClassName("katex-mathml")[0].textContent
  59. const terms = temp.split('\n')
  60. .map(line => line.trim())
  61. .filter(line => line.length > 0);
  62. // Return the last non-empty term, or empty string if none found
  63. if (terms.length>0){
  64. text += '$' + terms[terms.length - 1] + '$'
  65. }
  66. }
  67. }
  68. }
  69.  
  70. // For other elements, recurse into their children
  71. if (child.nodeType === Node.ELEMENT_NODE && !['span', 'script', 'math', 'img'].includes(child.nodeName.toLowerCase())) {
  72. text += getTextContentWithReplacements(url,child);
  73. }
  74. });
  75. }
  76. return text;
  77. }
  78.  
  79. (function() {
  80. 'use strict';
  81.  
  82. // Create the button element
  83. const button = document.createElement('button');
  84. button.textContent = 'Copy';
  85. button.style.position = 'absolute';
  86. button.style.display = 'none';
  87. button.style.zIndex = '1000';
  88.  
  89. // Append the button to the body
  90. document.body.appendChild(button);
  91.  
  92. // Function to handle button click
  93. button.addEventListener('click', function() {
  94. const selectedText = window.getSelection();
  95. if (selectedText) {
  96. myfunction(selectedText);
  97. }
  98. button.style.display = 'none'; // Hide the button after click
  99. });
  100.  
  101. let previousSelectedText = '';
  102.  
  103. document.addEventListener('mouseup', function(event) {
  104. const selectedText = window.getSelection().toString().trim();
  105.  
  106. // Only show the button if the selected text has changed
  107. if (selectedText && selectedText !== previousSelectedText) {
  108. const x = event.pageX + 5;
  109. const y = event.pageY + 5;
  110. button.style.left = `${x}px`;
  111. button.style.top = `${y}px`;
  112. button.style.display = 'block';
  113. previousSelectedText = selectedText; // Update the previous selection
  114. } else {
  115. button.style.display = 'none';
  116. previousSelectedText = ''; // Reset previous selection if no text is selected
  117. }
  118. });
  119.  
  120.  
  121. // Custom function to process the selected text
  122. function myfunction(selection) {
  123. let url = window.location.href
  124. let range = selection.getRangeAt(0);
  125. //console.log('Text selected:', selection.toString()); // Log selected text
  126. let c=range.cloneContents();
  127. let text = getTextContentWithReplacements(url,c);
  128. navigator.clipboard.writeText(text);
  129. }
  130. })();