JSON paste on textarea

Paste JSON on textarea

  1. // ==UserScript==
  2. // @name JSON paste on textarea
  3. // @version 0.6
  4. // @description Paste JSON on textarea
  5. // @match https://*/*
  6. // @grant none
  7. // @namespace https://greatest.deepsurf.us/users/371179
  8. // ==/UserScript==
  9. (function() {
  10. 'use strict';
  11.  
  12. /*
  13.  
  14. -- Example --
  15. https://jsonformatter.curiousconcept.com/
  16. "{\"a\":1,\"b\":2,\"c\":3,\"d\":\"A\",\"e\":\"B\",\"f\":\"C\"}"
  17.  
  18. */
  19.  
  20. function getClipText(evt) {
  21.  
  22. var text;
  23. var clp = (evt.originalEvent || evt).clipboardData;
  24. if (clp === undefined || clp === null) {
  25. text = window.clipboardData.getData("text") || null;
  26. } else {
  27. text = clp.getData('text/plain') || null;
  28. }
  29. return text;
  30.  
  31. }
  32.  
  33. // =========================================================================================
  34. // https://stackoverflow.com/questions/7464282/javascript-scroll-to-selection-after-using-textarea-setselectionrange-in-chrome
  35.  
  36. function setSelectionRange(textarea, selectionStart, selectionEnd) {
  37. // First scroll selection region to view
  38. const fullText = textarea.value;
  39. textarea.value = fullText.substring(0, selectionEnd);
  40. // For some unknown reason, you must store the scollHeight to a variable
  41. // before setting the textarea value. Otherwise it won't work for long strings
  42. const scrollHeight = textarea.scrollHeight
  43. textarea.value = fullText;
  44. let scrollTop = scrollHeight;
  45. const textareaHeight = textarea.clientHeight;
  46. if (scrollTop > textareaHeight) {
  47. // scroll selection to center of textarea
  48. scrollTop -= textareaHeight / 2;
  49. } else {
  50. scrollTop = 0;
  51. }
  52. textarea.scrollTop = scrollTop;
  53.  
  54. // Continue to set selection range
  55. textarea.setSelectionRange(selectionStart, selectionEnd);
  56. }
  57. // =========================================================================================
  58.  
  59.  
  60. if (document.queryCommandSupported("insertText")) {
  61.  
  62. var object = {
  63.  
  64. callback: function(str) {
  65.  
  66. var targetElm = this.targetElm;
  67. var clipText = this.clipText;
  68.  
  69. var newClipText = typeof str == 'string' ? str : clipText;
  70. if (newClipText != "") {
  71.  
  72.  
  73. var oldText = targetElm.value
  74. document.execCommand("insertText", false, newClipText);
  75.  
  76. if ('selectionStart' in targetElm) {
  77. var afterChange = () => {
  78. var newText = targetElm.value;
  79. if (oldText == newText) return window.requestAnimationFrame(afterChange);
  80. setSelectionRange(targetElm, targetElm.selectionStart, targetElm.selectionEnd);
  81. };
  82.  
  83. window.requestAnimationFrame(afterChange);
  84.  
  85. }
  86. }
  87.  
  88. }
  89. };
  90.  
  91. var JF_safeObjects=[];
  92.  
  93. var makeJFunction = (() => {
  94. var a = document.createElement('iframe');
  95. a.style.position = 'absolute';
  96. a.style.left = '-99px';
  97. a.style.top = '-99px';
  98. a.src = "about:blank"; //userscript can access "about:blank"
  99. a.width = "1";
  100. a.height = "1";
  101. document.documentElement.appendChild(a)
  102. // it is assumed that the "contentWindow" is immediately available after appendChild
  103. var JFunction;
  104. try {
  105. JFunction = (a.contentWindow || window).Function;
  106. } catch (e) {
  107. JFunction = window.Function
  108. }
  109.  
  110. document.documentElement.removeChild(a)
  111.  
  112. var res2 = null;
  113. try {
  114. var res = new JFunction('return Object.keys(window);')(); // avoid no access to JFunction
  115. res2 = [...res]; // transfer the js array object to the current framework
  116. } catch (e) {}
  117.  
  118. if (res2 && 'forEach' in res2) {
  119. JF_safeObjects=res2;
  120. }else{
  121. JFunction = window.Function;
  122. JF_safeObjects=[];
  123. }
  124.  
  125. return JFunction
  126. });
  127.  
  128.  
  129. var JFunction = null;
  130. document.addEventListener('paste', function(evt) {
  131.  
  132. var clipText = getClipText(evt)
  133. if (clipText === null || typeof clipText != 'string') return;
  134.  
  135. var targetElm = evt.target;
  136.  
  137. if (!targetElm) return;
  138.  
  139. switch (targetElm.tagName) {
  140. case 'TEXTAREA':
  141. break;
  142. default:
  143. return;
  144. }
  145.  
  146. var testingStr=clipText.replace(/[0-9]+/g,'0')
  147. testingStr=testingStr.replace(/[a-zA-Z\u4E00-\u9FFF]+/g,'z')
  148. if (/[\[\{][\s\S]*[\]\}]/.test(testingStr)&&/[\'\"\`][\s\S]*[\'\"\`]/.test(testingStr)){}else{ return;}
  149.  
  150. var testP = testingStr.replace(/[0z\/\%\-\+\_\.\;\$\#]+/g, '').trim();
  151. var testR = /^[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+$/
  152. if (!testP) {
  153. return;
  154. }
  155. if (!testR.test(testP)) return;
  156.  
  157. object.targetElm = targetElm;
  158. object.clipText = clipText;
  159.  
  160. // JS-safe Function
  161. JFunction = JFunction || makeJFunction();
  162.  
  163. //window.JF = JFunction
  164.  
  165.  
  166.  
  167. var res = null;
  168. try {
  169. res = new JFunction(...JF_safeObjects,'return (' + clipText + ');')(); //backbracket to avoid return newline -> undefined
  170. } catch (e) {}
  171.  
  172. //console.log(res)
  173.  
  174. if (typeof res == 'string') {
  175. console.log('userscript - there is a text convertion to your pasted content');
  176. evt.preventDefault();
  177. object.callback(res);
  178. }
  179.  
  180.  
  181. });
  182. }
  183.  
  184. // Your code here...
  185. })();