Selection Context

Get the selected text along with text before and after the selection

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/528822/1550450/Selection%20Context.js

  1. // ==UserScript==
  2. // @name Selection Context
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1.2
  5. // @description Get the selected text along with text before and after the selection
  6. // @author RoCry
  7. // @license MIT
  8. // ==/UserScript==
  9.  
  10. /**
  11. * Gets the selected text along with text before and after the selection
  12. * @param {number} tryContextLength - Desired length of context to try to collect (before + after selection)
  13. * @returns {Object} Object containing selectedHTML, selectedText, textBefore, textAfter, paragraphText
  14. */
  15. function GetSelectionContext(tryContextLength = 500) {
  16. const MAX_CONTEXT_LENGTH = 8192; // 8K characters max (reduced from 16K)
  17. const actualContextLength = Math.min(tryContextLength, MAX_CONTEXT_LENGTH);
  18. const halfContextLength = Math.floor(actualContextLength / 2);
  19.  
  20. const selection = window.getSelection();
  21.  
  22. if (!selection || selection.rangeCount === 0 || selection.toString().trim() === '') {
  23. return { selectedHTML: null, selectedText: null, textBefore: null, textAfter: null, paragraphText: null };
  24. }
  25.  
  26. const range = selection.getRangeAt(0);
  27. const selectedText = selection.toString().trim();
  28. // Improved HTML extraction
  29. let selectedHTML;
  30. try {
  31. // Method 1: Try to get HTML with surrounding elements
  32. const clonedRange = range.cloneRange();
  33. const container = document.createElement('div');
  34. container.appendChild(clonedRange.cloneContents());
  35. // If selection starts/ends in the middle of an element, we need to recreate parent structure
  36. const parentElement = range.commonAncestorContainer.nodeType === Node.TEXT_NODE
  37. ? range.commonAncestorContainer.parentElement
  38. : range.commonAncestorContainer;
  39. if (parentElement && parentElement.nodeName !== 'BODY') {
  40. // Get the parent element's tag name and recreate it
  41. const tagName = parentElement.nodeName.toLowerCase();
  42. selectedHTML = `<${tagName}>${container.innerHTML}</${tagName}>`;
  43. } else {
  44. selectedHTML = container.innerHTML;
  45. }
  46. } catch (e) {
  47. // Fallback method
  48. console.error('Error extracting HTML from selection:', e);
  49. selectedHTML = selectedText;
  50. }
  51.  
  52. // Helper function to get text nodes in document order
  53. function getTextNodesIn(node) {
  54. const textNodes = [];
  55. const walk = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
  56. let currentNode;
  57. while (currentNode = walk.nextNode()) {
  58. textNodes.push(currentNode);
  59. }
  60. return textNodes;
  61. }
  62.  
  63. // Get all text nodes in document
  64. const allTextNodes = getTextNodesIn(document.body);
  65.  
  66. // Find start and end text nodes of the selection
  67. const startNode = range.startContainer;
  68. const endNode = range.endContainer;
  69.  
  70. let textBefore = '';
  71. let textAfter = '';
  72.  
  73. // Collect text before the selection
  74. let beforeIndex = allTextNodes.findIndex(node => node === startNode) - 1;
  75. let currentLength = 0;
  76.  
  77. // First add partial text from the start node itself
  78. if (startNode.nodeType === Node.TEXT_NODE) {
  79. textBefore = startNode.textContent.substring(0, range.startOffset) + textBefore;
  80. currentLength = textBefore.length;
  81. }
  82.  
  83. // Then add text from previous nodes
  84. while (beforeIndex >= 0 && currentLength < halfContextLength) {
  85. const node = allTextNodes[beforeIndex];
  86. const nodeText = node.textContent;
  87.  
  88. // Add the entire node's text
  89. textBefore = nodeText + '\n' + textBefore;
  90. currentLength += nodeText.length;
  91.  
  92. beforeIndex--;
  93. }
  94.  
  95. // If we didn't get enough context, add ellipsis
  96. if (beforeIndex >= 0) {
  97. textBefore = '...\n' + textBefore;
  98. }
  99.  
  100. // Collect text after the selection
  101. let afterIndex = allTextNodes.findIndex(node => node === endNode) + 1;
  102. currentLength = 0;
  103.  
  104. // First add partial text from the end node itself
  105. if (endNode.nodeType === Node.TEXT_NODE) {
  106. textAfter += endNode.textContent.substring(range.endOffset);
  107. currentLength = textAfter.length;
  108. }
  109.  
  110. // Then add text from subsequent nodes
  111. while (afterIndex < allTextNodes.length && currentLength < halfContextLength) {
  112. const node = allTextNodes[afterIndex];
  113. const nodeText = node.textContent;
  114.  
  115. // Add the entire node's text
  116. textAfter += nodeText + '\n';
  117. currentLength += nodeText.length;
  118.  
  119. afterIndex++;
  120. }
  121.  
  122. // If we didn't get all the text, add ellipsis
  123. if (afterIndex < allTextNodes.length) {
  124. textAfter += '\n...';
  125. }
  126.  
  127. // Clean up and trim the text
  128. textBefore = textBefore.trim();
  129. textAfter = textAfter.trim();
  130.  
  131. // Combine everything for paragraph text
  132. const paragraphText = (textBefore + ' ' + selectedText + ' ' + textAfter).trim();
  133.  
  134. return { selectedHTML, selectedText, textBefore, textAfter, paragraphText };
  135. }
  136.  
  137. // Export the function for use in other scripts
  138. if (typeof module !== 'undefined' && module.exports) {
  139. module.exports = { GetSelectionContext };
  140. } else {
  141. // For direct browser use
  142. window.SelectionUtils = window.SelectionUtils || {};
  143. window.SelectionUtils.GetSelectionContext = GetSelectionContext;
  144. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址