Greasy Fork is available in English.

Auto Surround and Closing

Automatically closes parentheses, etc.

  1. // ==UserScript==
  2. // @name Auto Surround and Closing
  3. // @name:ja カッコとかを自動閉じ
  4. // @description:ja 自動でカッコとかクォーテーションを閉じる
  5. // @namespace https://yakisova.com
  6. // @version 1.2.0
  7. // @description Automatically closes parentheses, etc.
  8. // @author yakisova41
  9. // @match http://*/*
  10. // @match https://*/*
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. 'use strict';
  16.  
  17. const tokens = {
  18. '"': {
  19. start: '"',
  20. close: '"',
  21. surround: true,
  22. closing: true
  23. },
  24. "'": {
  25. start: '"',
  26. close: '"',
  27. surround: true,
  28. closing: true
  29. },
  30. "`": {
  31. start: '`',
  32. close: '`',
  33. surround: true,
  34. closing: true
  35. },
  36. "(": {
  37. start: '(',
  38. close: ')',
  39. surround: true,
  40. closing: true
  41. },
  42. "[": {
  43. start: '[',
  44. close: ']',
  45. surround: true,
  46. closing: true
  47. },
  48. "<": {
  49. start: '<',
  50. close: '>',
  51. surround: true,
  52. closing: false
  53. },
  54. "{": {
  55. start: '{',
  56. close: '}',
  57. surround: true,
  58. closing: true
  59. }
  60. }
  61.  
  62.  
  63. function inputListener(elem) {
  64. let valueState = "";
  65.  
  66. elem.addEventListener("keydown", (e)=>{
  67. if(Object.keys(tokens).includes(e.key)) {
  68. const { selectionStart, selectionEnd } = e.target;
  69. const {start, close, surround, closing} = tokens[e.key]
  70.  
  71. const before = valueState.slice(0, selectionStart);
  72. const after = valueState.slice(selectionEnd, valueState.length);
  73.  
  74. if(selectionStart !== selectionEnd && surround) {
  75. e.preventDefault();
  76.  
  77. const selected = valueState.slice(selectionStart, selectionEnd);
  78. e.target.value = `${before}${start}${selected}${close}${after}`;
  79. e.target.setSelectionRange(selectionStart + 1, selectionEnd + 1);
  80.  
  81. }
  82. else if(closing) {
  83. e.preventDefault();
  84.  
  85. e.target.value = `${before}${start}${close}${after}`;
  86. e.target.setSelectionRange(selectionEnd+ 1, selectionEnd + 1);
  87.  
  88. const backspaceHandler = (e)=>{
  89. if(e.key === "Backspace") {
  90. e.preventDefault();
  91. const { selectionStart, selectionEnd } = e.target;
  92. const before = valueState.slice(0, selectionStart - 1);
  93. const after = valueState.slice(selectionEnd + 1, valueState.length);
  94. e.target.value = `${before}${after}`;
  95. e.target.setSelectionRange(selectionStart - 1, selectionStart - 1);
  96. }
  97. elem.removeEventListener("keydown", backspaceHandler);
  98. }
  99. elem.addEventListener("keydown", backspaceHandler)
  100. } (dawd)
  101. }
  102. valueState = e.target.value;
  103. });
  104. }
  105.  
  106. setInterval(()=>{
  107. const inputs = document.querySelectorAll(`
  108. input[type="text"]:not(.attached-auto-surround-and-closing),
  109. input[type="search"]:not(.attached-auto-surround-and-closing),
  110. textarea:not(.attached-auto-surround-and-closing)
  111. `);
  112. inputs.forEach(input => {
  113. console.log(input)
  114. inputListener(input)
  115. input.classList.add("attached-auto-surround-and-closing")
  116. });
  117.  
  118. }, 100);