🏠 Home 

Easy Markdown for StackExchange

Adds "Markdown" and "Copy" buttons to display original Markdown content in StackExchange sites.


Install this script?
// ==UserScript==
// @name Easy Markdown for StackExchange
// @name:zh-CN 在StackExchange中显示Markdown
// @version 2.4
// @author Murphy Lo (http://github.com/MurphyLo)
// @description Adds "Markdown" and "Copy" buttons to display original Markdown content in StackExchange sites.
// @description:zh-CN 在StackExchange网站上添加“Markdown”和“Copy”按钮,以显示原始Markdown内容
// @license GNU GPL v3 (http://www.gnu.org/copyleft/gpl.html)
// @match https://*.stackoverflow.com/questions/*
// @match https://*.superuser.com/questions/*
// @match https://*.serverfault.com/questions/*
// @match https://*.stackexchange.com/questions/*
// @match https://*.askubuntu.com/questions/*
// @match https://*.math.stackexchange.com/questions/*
// @match https://*.tex.stackexchange.com/questions/*
// @match https://*.english.stackexchange.com/questions/*
// @match https://*.gaming.stackexchange.com/questions/*
// @match https://*.physics.stackexchange.com/questions/*
// @match https://*.chemistry.stackexchange.com/questions/*
// @match https://*.biology.stackexchange.com/questions/*
// @match https://*.programmers.stackexchange.com/questions/*
// @match https://*.electronics.stackexchange.com/questions/*
// @grant none
// @namespace https://greasyfork.org/users/1224148
// ==/UserScript==
// This script is a modified version of an original script by Manish Goregaokar (http://stackapps.com/users/10098/manishearth)
// Original script: https://github.com/Manishearth/Manish-Codes/raw/master/StackExchange/PrintPost.user.js
// The original script is licensed under the GNU GPL v3 (http://www.gnu.org/copyleft/gpl.html)
// Modifications made by Murphy Lo
(async function() {
'use strict';
// Function to fetch content of a post
async function fetchMarkdown(postId) {
const response = await fetch(`/posts/${postId}/edit-inline`);
// Check user login status.
if (response.status === 404) {
return "--- Please LOG IN StackExchange/Stackoverflow to view and copy the Markdown content. ---";
}
const data = await response.text();
let markdown = data.match(/<textarea[^>]*>([\s\S]*?)<\/textarea>/)[1];
// Decode HTML entities
return decodeHtmlEntities(markdown);
}
// Function to decode HTML entities from the content into Markdown plain text
function decodeHtmlEntities(str) {
const tempElement = document.createElement('div');
tempElement.innerHTML = str;
return tempElement.textContent;
}
// Function to show markdown content in a modal
function showMarkdown(event) {
// Prevent the default action
event.preventDefault();
// Disable scrolling on the main page
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
document.body.style.overflow = 'hidden';
document.body.style.paddingRight = `${scrollbarWidth}px`;
// Add paddingRight to fixed positioned elements
const fixedElements = document.querySelectorAll('header.s-topbar');
fixedElements.forEach(el => el.style.paddingRight = `${scrollbarWidth}px`);
// Create a modal to display the markdown (updated style)
const modal = document.createElement('div');
modal.style.cssText = `
position: fixed;
z-index: 5051;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: none;
background-color: rgba(0,0,0,0.5);`;
const modalContent = document.createElement('div');
modalContent.style.cssText = `
background-color: #FFF;
margin: 5% auto;
padding: 20px;
border: 1px solid #888;
width: 70%;
max-height: 90%;
overflow-y: auto;
box-sizing: border-box;
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.3);`;
// Updated close button style
const closeButton = document.createElement('span');
closeButton.style.cssText = `
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
margin-left: 10px;`;
closeButton.textContent = '✕';
closeButton.onmouseover = () => closeButton.style.color = 'black';
closeButton.onmouseout = () => closeButton.style.color = '#aaa';
const markdownElement = document.createElement('pre');
markdownElement.style.cssText = `
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
overflow-y: auto;`;
markdownElement.textContent = this.markdownContent;
modalContent.appendChild(closeButton);
modalContent.appendChild(markdownElement);
modal.appendChild(modalContent);
document.body.appendChild(modal);
// Close modal behaviors
function closeModal() {
// Removing the modal from the DOM
document.body.removeChild(modal);
document.removeEventListener('keydown', handleKeyDown);
// Re-enable scrolling on the main page and remove the paddingRight
document.body.style.overflow = '';
document.body.style.paddingRight = '';
// Remove paddingRight from fixed positioned elements
const fixedElements = document.querySelectorAll('header.s-topbar');
fixedElements.forEach(el => el.style.paddingRight = '');
}
// Click `x` to close modal
closeButton.onclick = closeModal;
// Press `Esc` to close modal
const handleKeyDown = (event) => event.keyCode === 27 && closeModal(); // 27 is the keyCode for the Esc key
document.addEventListener('keydown', handleKeyDown);
// Click modal background to close modal
modal.onclick = (e) => e.target === modal && closeModal();
}
// Function to copy text to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
// console.log('Markdown content copied to clipboard');
} catch (err) {
console.error('Failed to copy Markdown content: ', err);
}
}
// Add "Markdown" and "Copy" buttons to each post
const posts = document.querySelectorAll('.question, .answer');
for (const post of posts) {
const postMenu = post.querySelector('.d-flex.gs8.s-anchors.s-anchors__muted.fw-wrap');
const separator = document.createElement('span');
separator.className = 'lsep';
separator.textContent = '|';
postMenu.appendChild(separator);
// Add Markdown button
const printButton = document.createElement('a');
printButton.href = '#';
printButton.textContent = 'Markdown';
printButton.title = 'View this post\'s Markdown content';
printButton.onclick = showMarkdown;
printButton.style.cssText = `
background-color: #f5f5f5;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;`;
printButton.onmouseover = () => printButton.style.backgroundColor = '#e0e0e0';
printButton.onmouseout = () => printButton.style.backgroundColor = '#f5f5f5';
const printButtonWrapper = document.createElement('div');
printButtonWrapper.className = 'flex--item';
printButtonWrapper.appendChild(printButton);
postMenu.appendChild(printButtonWrapper);
// Add Copy button
const copyButton = document.createElement('a');
copyButton.href = '#';
copyButton.textContent = 'Copy';
copyButton.title = 'Copy this post\'s Markdown content to clipboard';
copyButton.onclick = (event) => {
event.preventDefault();
copyToClipboard(printButton.markdownContent);
copyButton.textContent = 'Copied!';
setTimeout(() => copyButton.textContent = 'Copy', 2000);
};
copyButton.style.cssText = `
background-color: #f5f5f5;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
margin-left: 5px;
transition: background-color 0.3s;`;
copyButton.onmouseover = () => copyButton.style.backgroundColor = '#e0e0e0';
copyButton.onmouseout = () => copyButton.style.backgroundColor = '#f5f5f5';
const copyButtonWrapper = document.createElement('div');
copyButtonWrapper.className = 'flex--item';
copyButtonWrapper.appendChild(copyButton);
postMenu.appendChild(copyButtonWrapper);
// Fetch and store markdown content
const postId = post.dataset.questionid || post.dataset.answerid;
printButton.markdownContent = await fetchMarkdown(postId);
}
})();