Surrounded

Surrounds selected text on web pages with pairs of characters when typed, keeps selection unchanged.

目前为 2019-01-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Surrounded
  3. // @namespace cpriest
  4. // @version 0.2
  5. // @description Surrounds selected text on web pages with pairs of characters when typed, keeps selection unchanged.
  6. // @author Clint Priest
  7. // @homepage https://github.com/cpriest/userscripts/tree/master/surrounded
  8. // @match http*://
  9. // @grant none
  10. // @license MIT
  11. // @compatible firefox
  12. // @compatible chrome
  13. // @compatible opera
  14. // @compatible safari
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. const CTRL = 1,
  21. ALT = 2,
  22. SHIFT = 4;
  23.  
  24. const ActiveKeys = [`'`, `"`, '{', '}', '[', ']', '`', '*', '_', '<', '>',];
  25.  
  26. /**
  27. * Returns true if we work with the passed in elem
  28. *
  29. * @param {Element} elem
  30. *
  31. * @returns boolean
  32. */
  33. function WeWorkWithThisElement(elem) {
  34. if(elem.tagName == 'TEXTAREA')
  35. return true;
  36.  
  37. if(elem.tagName == 'INPUT') {
  38. if('selectionStart' in elem || 'selectionEnd' in elem)
  39. return true;
  40. }
  41. return false;
  42. }
  43.  
  44. function note(...args) {
  45. console.log(...args);
  46. }
  47.  
  48. /**
  49. * Surrounds the given elements selection with the character set
  50. *
  51. * @param {HTMLInputElement|HTMLTextAreaElement} elem
  52. * @param key
  53. */
  54. function Surround(elem, key) {
  55. let { selectionStart, selectionEnd, selectionDirection } = elem;
  56.  
  57. let leftKey = key + '',
  58. rightKey = key + '',
  59. leftValue = elem.value.substring(0, elem.selectionStart),
  60. value = elem.value.substring(elem.selectionStart, elem.selectionEnd),
  61. rightValue = elem.value.substring(elem.selectionEnd);
  62.  
  63. switch(leftKey) {
  64. case '{':
  65. rightKey = '}';
  66. break;
  67. case '}':
  68. rightKey = '{';
  69. [leftKey, rightKey] = [rightKey, leftKey];
  70. break;
  71. case '[':
  72. rightKey = ']';
  73. break;
  74. case ']':
  75. rightKey = '[';
  76. [leftKey, rightKey] = [rightKey, leftKey];
  77. break;
  78. case '<':
  79. rightKey = '>';
  80. break;
  81. case '>':
  82. rightKey = '<';
  83. [leftKey, rightKey] = [rightKey, leftKey];
  84. break;
  85. }
  86.  
  87. // Remove Mode
  88. if(leftValue.substr(-1) === leftKey && rightValue.substr(0, 1) === rightKey) {
  89. leftValue = leftValue.substr(0, leftValue.length - 1);
  90. rightValue = rightValue.substr(1);
  91. leftKey = rightKey = '';
  92. selectionStart--;
  93. selectionEnd--;
  94. } else {
  95. // Add Mode
  96. selectionStart++;
  97. selectionEnd++;
  98. }
  99.  
  100. elem.value = `${leftValue}${leftKey}${value}${rightKey}${rightValue}`;
  101. elem.selectionStart = selectionStart;
  102. elem.selectionEnd = selectionEnd;
  103. }
  104.  
  105. window.document.addEventListener('keydown',
  106. /** @param {KeyboardEvent} e */e => {
  107. e.mods = (e.ctrlKey) + (e.altKey << 1) + (e.shiftKey << 2);
  108.  
  109. if(e.mods > 0 && e.mods !== 4)
  110. return; // note(`${e.key}: CTRL/ALT active e.mods=${e.mods}`);
  111.  
  112. if(ActiveKeys.indexOf(e.key) == -1)
  113. return; // note(`${e.key}: not a key we care about`);
  114.  
  115. if(!document.activeElement)
  116. return; // note(`${e.key}: no valid activeElement: %o`, document.activeElement);
  117.  
  118. let ae = document.activeElement;
  119. if(!WeWorkWithThisElement(ae))
  120. return; // note(`${e.key}: We don't work with: %o`, ae);
  121.  
  122. if(ae.selectionStart === ae.selectionEnd)
  123. return; // note(`${e.key}: No characters are selected, start=${ae.selectionStart}, end=${ae.selectionEnd}` );
  124.  
  125. Surround(ae, e.key);
  126.  
  127. e.preventDefault();
  128. e.stopPropagation();
  129.  
  130. }, true);
  131. })();