Word & Text Replace

replaces text with other text.

当前为 2019-09-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Word & Text Replace
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.3.1
  5. // @description replaces text with other text.
  6. // @author listfilterErick
  7. // @grant none
  8.  
  9. // @match *://*/*
  10.  
  11. // @require http://code.jquery.com/jquery-1.12.4.min.js
  12. // @require https://greasyfork.org/scripts/5392-waitforkeyelements/code/WaitForKeyElements.js?version=115012
  13.  
  14. // @licence CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/
  15. // @licence GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
  16. // ==/UserScript==
  17. /*jshint esversion: 6*/
  18.  
  19. /*
  20. Update Log 1.3.1
  21. - new options:
  22. -- logMatches, logChangedText
  23. -- dontMarkDivs, checkHyperlinkElements
  24. - cleanup: changed variable names, cleaned up function code.
  25.  
  26. * Text nodes are trimmed before checking but changed text is not trimmed unless specified in the regex.
  27. */
  28.  
  29. (function () {
  30.  
  31. let replaceRules = [];
  32. /*
  33. regex reference
  34. \b: word boundry
  35. \W: any non-alpha character
  36. */
  37. if (1) {
  38. replaceRules.push(
  39. // basic examples:
  40. //[/(.\W?)*/i, 'words'], //replace all text instances with "words".
  41. //[/\w/gi, 'a'], //replace all characters with an "a" character.
  42. //[/match/gi, 'a'], //matches "match" in "ABmarchCD" and "red match".
  43. //[/\bmatch\b/gi, 'a'], //does not match "ABmatchesCD" but does match "this match is red".
  44. //[/scripts/gi, 'dictionaries'],
  45. //[/script/gi, 'dictionary'],
  46. //[/(web)?site/gi, 'webzone'],
  47. );
  48. // separated just for an example of an option of grouping/sorting.
  49. replaceRules.push(
  50. //[/user/gi, 'individual'],
  51. //[/\buse\b/gi, 'utilize'],
  52. );
  53. }
  54. /*
  55. #### note on moving rules to a seperate userscript ####
  56. https://wiki.greasespot.net/UnsafeWindow
  57. unsafeWindow.replaceRules = replaceRules; //set rules(page scope) to rules(script scope)
  58. replaceRules = unsafeWindow.replaceRules; //set rules(script scope) to rules(page scope)
  59. */
  60.  
  61. const showReplaceButton = 0; // set to 1 to show a button to manually run this script.
  62. const buttonTransparency = .2; // set to a value between 0 and 1, 1 is no transparency, .5 is 50% transparency.
  63. const dynamicChecking = 1; // set to 1 to run the script automatically when new image elements are detected.
  64.  
  65. const showLogMessages = 0; // set to 1 to log script messages, overrides the following log options.
  66. const logMatches = 1; // set to 1 to log matches to the console.
  67. const logChangedText = 0; // set to 1 to log changed text to the console.
  68. const logRuntimes = 1; // set to 1 to log function runtimes to the console.
  69.  
  70. const dontMarkDivs = 1; // set to 1 to not mark divs as checked, solves some site issues.
  71. // setting to 1 would make dynamic checks recheck checked divs.
  72. const checkHyperlinkElements = 1; // set to 1 to check unchecked hyperlink elements.
  73.  
  74. function consolelog(text, showOption) {
  75. if (showLogMessages && showOption) {
  76. console.log(text);
  77. }
  78. }
  79.  
  80. let titleChecked = 0;
  81. let nodeCounter = 1;
  82. let aCounter = 1;
  83.  
  84. // ==== replaceText() =========================================================================|
  85. function replaceText() {
  86.  
  87. if (logRuntimes) {
  88. var startTime = performance.now();
  89. }
  90.  
  91. let numTerms = replaceRules.length;
  92. let ruleMatched = 0;
  93.  
  94. // ==== title element =====================================================================|
  95. let titleText = jQuery("title").text();
  96. if (titleText && !titleChecked) {
  97. for (let index = 0; index < numTerms; index++) {
  98. if (replaceRules[index][0].test(titleText)) {
  99. consolelog("(title match): "+ titleText +" | "+ replaceRules[index][0], logMatches);
  100. titleText = titleText.replace(replaceRules[index][0], replaceRules[index][1]);
  101. jQuery("title").text(titleText);
  102. }
  103. }
  104. titleChecked = 1;
  105. }
  106.  
  107. // ==== text elements =====================================================================|
  108. let textWalker = document.createTreeWalker(
  109. document.body,
  110. NodeFilter.SHOW_TEXT,
  111. {
  112. acceptNode: function (node) {
  113. if (node.nodeValue.trim() &&
  114. !/CODE|SCRIPT|STYLE/.test(node.parentNode.nodeName) && // exclude scripts and style elements
  115. !/wr-checked/.test(node.parentNode.classList)) { // exclude checked elements
  116. return NodeFilter.FILTER_ACCEPT;
  117. }
  118. return NodeFilter.FILTER_SKIP;
  119. }
  120. },
  121. false
  122. );
  123. let textNode = textWalker.nextNode();
  124. while (textNode) {
  125. let currentText = textNode.nodeValue;
  126. let parentNode = textNode.parentNode;
  127. if (!dontMarkDivs || parentNode.nodeName != "DIV") { //supposedly adding a class to a div broke a site somehow.
  128. parentNode.classList.add("wr-checked");
  129. }
  130. for (let index = 0; index < numTerms; index++) {
  131. if (replaceRules[index][0].test(currentText.trim())) {// ## checks the trimmed text.
  132. ruleMatched = 1;
  133. consolelog(nodeCounter +" (text match): "+ currentText +" | "+ replaceRules[index][0], logMatches);
  134. currentText = currentText.replace(replaceRules[index][0], replaceRules[index][1]);
  135. }
  136. }
  137. if (ruleMatched) {
  138. ruleMatched = 0;
  139. textNode.nodeValue = currentText;
  140. consolelog(nodeCounter +" (text): "+ currentText.trim(), logChangedText);
  141. nodeCounter++;
  142. }
  143. textNode = textWalker.nextNode();
  144. }
  145.  
  146. // ==== hyperlink elements ================================================================|
  147. if (checkHyperlinkElements) {
  148. jQuery("a").each(function () {
  149. if (jQuery(this).children().length == 0 && //children() does not include text nodes.
  150. !jQuery(this).hasClass("wr-checked") &&
  151. this.innerHTML.trim()) {
  152.  
  153. let aText = this.innerHTML;
  154. for (let index = 0; index < numTerms; index++) {
  155. if (replaceRules[index][0].test(aText)) {
  156. ruleMatched = 1;
  157. consolelog(aCounter +" (a match): "+ aText.trim() +" | "+ replaceRules[index][0], logMatches);
  158. aText = aText.replace(replaceRules[index][0], replaceRules[index][1]);
  159. }
  160. }
  161. if (ruleMatched) {
  162. jQuery(this).text(aText);
  163. consolelog(aCounter +" (a) text: " + aText.trim(), logChangedText);
  164. aCounter++;
  165. ruleMatched = 0;
  166. }
  167. jQuery(this).addClass("wr-checked");
  168.  
  169. }
  170. });
  171. }
  172.  
  173. if (logRuntimes) {
  174. const endTime = performance.now();
  175. const runTime = ((endTime - startTime) / 1000).toFixed(2);
  176. if (runTime > 1) {
  177. consolelog('(WR) finished after ' + runTime + ' seconds.', 1);
  178. }else {
  179. consolelog('(WR) finished in less than 1 second.', 1);
  180. }
  181. }
  182.  
  183. } //end function replaceText()
  184.  
  185. replaceText();
  186. if (dynamicChecking) {
  187. jQuery(document).ready(waitForKeyElements("img", replaceText));
  188. //jQuery(window).on("load", function() { //after all initial images are loaded.
  189. //waitForKeyElements("img", replaceText);
  190. //});
  191. }
  192.  
  193. if (showReplaceButton) {
  194. if (!jQuery("#wt-buttons").length) {
  195. consolelog("(WR) created #wt-buttons.");
  196. jQuery("body").prepend("<div id='wt-buttons'><div id='wr-reset'>WR</div><div id='wt-close'>&times;</div></div>");
  197. jQuery("#wt-close").click(function () { jQuery("#wt-buttons").remove(); });
  198.  
  199. const webToolsCss =
  200. `<style type="text/css">
  201. #wt-buttons {
  202. width: 50px;
  203. display: block;
  204. opacity: `+ buttonTransparency + `;
  205. position: fixed;
  206. top: 0px;
  207. right: 0px;
  208. z-index: 999;
  209. }
  210. #wt-buttons:hover {
  211. opacity: 1;
  212. }
  213. #wt-buttons div {
  214. display: block !important;
  215. padding: 5px;
  216. border-radius: 5px;
  217. margin-top: 2px;
  218. font-size: initial !important;
  219. font-weight: bold;
  220. color: white;
  221. cursor: pointer;
  222. }
  223. #wt-close {
  224. background: #777777;
  225. text-align: center;
  226. }
  227. </style>`;
  228.  
  229. jQuery(document.body).append(webToolsCss);
  230. } else {
  231. jQuery("#wt-buttons").prepend("<div id='wr-reset'>WR</div>");
  232. }
  233. jQuery("#wr-reset").click(replaceText);
  234.  
  235. const wordReplaceCss =
  236. `<style type="text/css">
  237. #wr-reset {
  238. background: #ffb51b;
  239. }
  240. </style>`;
  241.  
  242. jQuery(document.body).append(wordReplaceCss);
  243. } // end if (showReplaceButton)
  244. })();