Hide backticks on Hackpad

Hide the ugly backticks around code-formatted text on Hackpad.

  1. // ==UserScript==
  2. // @name Hide backticks on Hackpad
  3. // @namespace http://zesty.ca/
  4. // @version 1.2
  5. // @description Hide the ugly backticks around code-formatted text on Hackpad.
  6. // @author Ka-Ping Yee
  7. // @match https://*.hackpad.com/*
  8. // @grant none
  9. // ==/UserScript==
  10. /* jshint -W097 */
  11. 'use strict';
  12.  
  13. function addGlobalStyle(css) {
  14. var head, style;
  15. head = document.getElementsByTagName('head')[0];
  16. if (!head) { return; }
  17. style = document.createElement('style');
  18. style.type = 'text/css';
  19. style.innerHTML = css;
  20. head.appendChild(style);
  21. }
  22.  
  23. if (typeof ace !== 'undefined') {
  24. // Make backticks very small and almost invisible. We don't set them
  25. // to display: none because that screws up the editor; you still have to
  26. // be able to insert and delete backticks to control formatting.
  27. addGlobalStyle('span { font-weight: normal; opacity: 0.9; }');
  28. addGlobalStyle('ul.listtype-code, div#sidediv, span.code { font-size: 95%; color: #600; }');
  29. addGlobalStyle('span.code { border-radius: 0; margin: 0 !important; padding: 1px 3px !important; box-shadow: none; background: #f4f4f4; }');
  30. addGlobalStyle('span.code.hidebackticks { user-select: none; font-size: 6px; font-family: arial; opacity: 0.2; margin: 0 -1px !important; padding: 1px 0 !important; }');
  31. addGlobalStyle('ul.listtype-code { margin-left: 26px; background: #f4f4f4; line-height: 1.1; }');
  32. addGlobalStyle('ul.listtype-code li { padding: 2px 3px; margin: 0 !important; }');
  33. addGlobalStyle('div#sidediv div { color: #ddd !important; margin-top: -2px; }');
  34. addGlobalStyle('a.lang-menu { border-bottom: none; color: #8c8; }');
  35.  
  36. var originalAceEditor = ace.editor;
  37. ace.editor = function(a, b) {
  38. var result = new originalAceEditor(a, b);
  39. var originalGetSpansForLine = result.getSpansForLine;
  40.  
  41. result.getSpansForLine = function(dummy, appender) {
  42. originalGetSpansForLine.call(result, dummy, function(text, cls) {
  43. if (cls.match(/ code$/)) {
  44. // We can't delete the backticks altogether or the next
  45. // pass of the formatter won't be able to tell that the
  46. // text should still be monospaced. So, we make separate
  47. // spans for the backticks and use CSS to hide them.
  48. text = text.replace(/^`(.*)`$/, '$1');
  49. appender('`', cls + ' hidebackticks');
  50. appender(text, cls);
  51. appender('`', cls + ' hidebackticks');
  52. } else appender(text, cls);
  53. });
  54. };
  55. return result;
  56. };
  57. }
  58.  
  59. // Whenever the user completes a text selection, this adjusts the ends of the
  60. // selection to avoid picking up leading or trailing backticks.
  61. document.body.addEventListener('mouseup', function() {
  62. var sel = window.getSelection();
  63. if (sel.rangeCount === 0) return;
  64. var range = sel.getRangeAt(0);
  65. var start = range.startContainer, soff = range.startOffset;
  66. var end = range.endContainer, eoff = range.endOffset;
  67. if (!start || !end || start === end) return;
  68. while (true) {
  69. if (start === end) break;
  70. if (start.textContent.substring(soff).trim() === '' ||
  71. start.parentNode.className.match(/ hidebackticks$/)) {
  72. start = start.parentNode.nextSibling.childNodes[0];
  73. soff = 0;
  74. range.setStart(start, soff);
  75. continue;
  76. }
  77. if (end.textContent.substring(0, eoff).trim() === '' ||
  78. end.parentNode.className.match(/ hidebackticks$/)) {
  79. end = end.parentNode.previousSibling.childNodes[0];
  80. eoff = end.textContent.length;
  81. range.setEnd(end, eoff);
  82. continue;
  83. }
  84. break;
  85. }
  86. sel.empty();
  87. sel.addRange(range);
  88. });