Selection Context

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

Skrip ini tidak untuk dipasang secara langsung. Ini adalah pustaka skrip lain untuk disertakan dengan direktif meta // @require https://update.greatest.deepsurf.us/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. }