Reddit Full Markdown Editor

Adds a full markdown editor with preview and draft saving to Reddit post and reply boxes

  1. // ==UserScript==
  2. // @name Reddit Full Markdown Editor
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Adds a full markdown editor with preview and draft saving to Reddit post and reply boxes
  6. // @author Mr.K
  7. // @match https://old.reddit.com/*
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Load SimpleMDE and CSS
  15. var simplemdeScript = document.createElement('script');
  16. simplemdeScript.src = 'https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js';
  17. document.head.appendChild(simplemdeScript);
  18.  
  19. var simplemdeCss = document.createElement('link');
  20. simplemdeCss.rel = 'stylesheet';
  21. simplemdeCss.href = 'https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css';
  22. document.head.appendChild(simplemdeCss);
  23.  
  24. // Add Custom Styles for the Popup
  25. GM_addStyle(`
  26. .markdown-editor-popup {
  27. position: fixed;
  28. top: 10%;
  29. left: 50%;
  30. transform: translateX(-50%);
  31. width: 80%;
  32. max-width: 800px;
  33. background: #fff;
  34. border: 1px solid #ccc;
  35. box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  36. z-index: 1000;
  37. display: none;
  38. }
  39. .markdown-editor-popup-header {
  40. background: #f6f6f6;
  41. padding: 10px;
  42. border-bottom: 1px solid #ccc;
  43. font-size: 16px;
  44. font-weight: bold;
  45. display: flex;
  46. justify-content: space-between;
  47. }
  48. .markdown-editor-popup-body {
  49. padding: 10px;
  50. }
  51. .markdown-editor-popup-footer {
  52. background: #f6f6f6;
  53. padding: 10px;
  54. border-top: 1px solid #ccc;
  55. display: flex;
  56. justify-content: flex-end;
  57. }
  58. .markdown-editor-drafts {
  59. margin-top: 10px;
  60. max-height: 200px;
  61. overflow-y: auto;
  62. border-top: 1px solid #ccc;
  63. padding-top: 10px;
  64. }
  65. .markdown-editor-draft-item {
  66. display: flex;
  67. justify-content: space-between;
  68. align-items: center;
  69. padding: 5px;
  70. cursor: pointer;
  71. }
  72. .markdown-editor-draft-item:hover {
  73. background: #e9e9e9;
  74. }
  75. .markdown-editor-draft-delete {
  76. background: red;
  77. color: white;
  78. border: none;
  79. cursor: pointer;
  80. padding: 5px;
  81. margin-left: 10px;
  82. }
  83. `);
  84.  
  85. function createPopup() {
  86. var popup = document.createElement('div');
  87. popup.className = 'markdown-editor-popup';
  88. popup.innerHTML = `
  89. <div class="markdown-editor-popup-header">
  90. Markdown Editor
  91. <button class="markdown-editor-popup-close">X</button>
  92. </div>
  93. <div class="markdown-editor-popup-body">
  94. <textarea id="markdown-editor-textarea"></textarea>
  95. <div class="markdown-editor-drafts"></div>
  96. </div>
  97. <div class="markdown-editor-popup-footer">
  98. <button class="markdown-editor-save-draft">Save Draft</button>
  99. <button class="markdown-editor-submit">Submit</button>
  100. </div>
  101. `;
  102. document.body.appendChild(popup);
  103.  
  104. var simplemde = new SimpleMDE({ element: document.getElementById('markdown-editor-textarea') });
  105. return { popup, simplemde };
  106. }
  107.  
  108. function openPopup(simplemde, target) {
  109. var popup = document.querySelector('.markdown-editor-popup');
  110. popup.style.display = 'block';
  111. simplemde.value(target.value);
  112.  
  113. // Load drafts
  114. var draftsContainer = document.querySelector('.markdown-editor-drafts');
  115. draftsContainer.innerHTML = '';
  116. var drafts = JSON.parse(localStorage.getItem('markdownEditorDrafts') || '[]');
  117. drafts.forEach((draft, index) => {
  118. var draftItem = document.createElement('div');
  119. draftItem.className = 'markdown-editor-draft-item';
  120. draftItem.innerHTML = `
  121. <span>${draft.substring(0, 50)}...</span>
  122. <button class="markdown-editor-draft-delete" data-index="${index}">Delete</button>
  123. `;
  124. draftItem.querySelector('span').onclick = () => simplemde.value(draft);
  125. draftItem.querySelector('.markdown-editor-draft-delete').onclick = () => {
  126. deleteDraft(index, simplemde, target);
  127. };
  128. draftsContainer.appendChild(draftItem);
  129. });
  130.  
  131. // Handle saving drafts
  132. document.querySelector('.markdown-editor-save-draft').onclick = () => {
  133. drafts.push(simplemde.value());
  134. localStorage.setItem('markdownEditorDrafts', JSON.stringify(drafts));
  135. alert('Draft saved!');
  136. openPopup(simplemde, target); // Refresh the drafts list
  137. };
  138.  
  139. // Handle submitting content
  140. document.querySelector('.markdown-editor-submit').onclick = () => {
  141. target.value = simplemde.value();
  142. popup.style.display = 'none';
  143. };
  144.  
  145. // Handle closing the popup
  146. document.querySelector('.markdown-editor-popup-close').onclick = () => {
  147. popup.style.display = 'none';
  148. };
  149. }
  150.  
  151. function deleteDraft(index, simplemde, target) {
  152. var drafts = JSON.parse(localStorage.getItem('markdownEditorDrafts') || '[]');
  153. drafts.splice(index, 1);
  154. localStorage.setItem('markdownEditorDrafts', JSON.stringify(drafts));
  155. alert('Draft deleted!');
  156. openPopup(simplemde, target); // Refresh the drafts list
  157. }
  158.  
  159. function init() {
  160. var { popup, simplemde } = createPopup();
  161.  
  162. document.querySelectorAll('.usertext-edit textarea').forEach(textarea => {
  163. var openEditorButton = document.createElement('button');
  164. openEditorButton.textContent = 'Open Markdown Editor';
  165. openEditorButton.style.display = 'block';
  166. openEditorButton.style.marginBottom = '10px';
  167. openEditorButton.onclick = () => openPopup(simplemde, textarea);
  168. textarea.parentNode.insertBefore(openEditorButton, textarea);
  169. });
  170. }
  171.  
  172. simplemdeScript.onload = init;
  173. })();