您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Use `code` for inline code. Automatically fix quotes in code tags. Link to a section of text easily.
当前为
// ==UserScript== // @name Medium: Editor For Programmers // @namespace https://github.com/Zren/ // @version 3 // @description Use `code` for inline code. Automatically fix quotes in code tags. Link to a section of text easily. // @author Zren // @icon https://medium.com/favicon.ico // @match https://medium.com/p/*/edit // @grant none // ==/UserScript== (function(){ function wrapInlineCode() { var tagBefore = '<code class="markup--code"><strong class="markup--strong">'; var tagAfter = '</strong></code>'; var sel = window.getSelection(); if (sel.type === 'Caret' && sel.focusNode.nodeName === "#text") { // Note: Does not trigger if first character in text node, since the focus isn't a Text node. var str = sel.focusNode.nodeValue; var before = str.substr(0, sel.focusOffset - 1); var after = str.substr(sel.focusOffset); console.log("Before: ", before); console.log("After: ", after); var index = before.lastIndexOf('`'); if (index >= 0) { // we just typed the right quote if (index === before.length-1) { // `` // Ignore } else { // `...` var range = document.createRange(); range.setStart(sel.focusNode, index); range.setEnd(sel.focusNode, sel.focusOffset); sel.removeAllRanges(); sel.addRange(range); var html = range.toString(); html = html.substr(1, html.length-2); // trim `` html = tagBefore + html + tagAfter + ' '; document.execCommand('insertHTML', false, html); range.collapse(false); // move cursor to end return; } } var index = after.indexOf('`'); if (index >= 0) { // we just typed the left quote if (index == 0) { // `` // Ignore } else { var range = document.createRange(); range.setStart(sel.focusNode, sel.focusOffset - 1); range.setEnd(sel.focusNode, sel.focusOffset + index + 1); sel.removeAllRanges(); sel.addRange(range); var html = range.toString(); html = html.substr(1, html.length-2); // trim `` html = tagBefore + html + tagAfter + ' '; document.execCommand('insertHTML', false, html); range.collapse(false); // move cursor to end return; } } } } function alwaysBrInPre(e) { var sel = window.getSelection(); if (sel.type === 'Caret' && sel.focusNode.nodeName === "#text") { console.log(sel.focusNode.nodeValue.length, sel.focusOffset, sel.focusNode.nodeValue.substr(sel.focusOffset), sel.focusNode); if (sel.focusOffset !== 0) return; // End of line = selecting start of next line. // Focused on start of line. var el = sel.focusNode; while (el) { if (!el.parentNode) break; // Don't run on #document element since it doesn't have el.hasAttribute if (el.classList && el.classList.contains('section-inner')) break; // Ignore everything outside the post itself. if (el != el.parentNode.firstChild) break; // Only match end of line = start of next line. if (el.parentNode.tagName == 'PRE') { // Insert linebreak <br> var secondPre = el.parentNode; var firstPre = secondPre.previousSibling; firstPre.appendChild(document.createElement('br')); // <br> removed during split var newFocusLine = document.createElement('br'); firstPre.appendChild(newFocusLine); // The actual <br> we wanted to enter. // Move all elements back into the first pre. while (secondPre.firstChild) { firstPre.appendChild(secondPre.firstChild); } // Delete the second <pre> // We can't remove it since it will break the entire editor... secondPre.appendChild(document.createElement('br')); //secondPre.remove(); //document.execCommand('delete'); // Move cursor to new line. var range = document.createRange(); range.setStart(newFocusLine, 0); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); e.preventDefault(); } el = el.parentNode; } } } function onKeyDown(e) { if (e.key === '`') { setTimeout(wrapInlineCode, 100); // Wait for ` to be written so we can replace it } else if (e.keyCode == 9) { // Tab e.preventDefault(); } else if (e.keyCode == 13) { // Enter alwaysBrInPre(e); } else if (e.key == '6' && e.ctrlKey && e.altKey) { console.log('CTRL+ALT+6', e); } else { console.log('Key:', e.key, e.ctrlKey, e.altKey); } } function fixQuotes() { // Fix quotes in <pre> and <code> tags. setInterval(function(){ var codeTags = document.querySelectorAll('pre, code'); for (var tag of codeTags) { if (tag.innerHTML.indexOf('“') >= 0 || tag.innerHTML.indexOf('”') >= 0) { tag.innerHTML = tag.innerHTML.replace('“', '"').replace('”', '"'); } } }, 1000); } function showPermalink() { // Setup (temporary) permalink to line. var tag = document.createElement('a'); tag.style.position = 'absolute'; tag.style.display = 'block'; tag.style.top = '-9999px'; tag.style.left = 0; tag.style.color = '#888'; tag.innerHTML = '¶'; //'[link]'; document.body.appendChild(tag); function onMouseOver(e) { var el = e.relatedTarget || e.target; while (el) { if (!el.parentNode) break; // Don't run on #document element since it doesn't have el.hasAttribute if (el.classList.contains('section-inner')) break; // Ignore everything outside the post itself. if (el.hasAttribute('name')) { showTag(el) break; } el = el.parentNode; } } function showTag(el) { var rect = el.getBoundingClientRect(); var url = document.querySelector('link[rel="canonical"]').href; url = url.substr(0, url.length - '/edit'.length); url += '#' + el.getAttribute('name'); tag.href = 'javascript:window.history.replaceState({}, "", "' + url + '")'; var tagGuide = document.querySelector('.section-inner'); var tagGuideRect = tagGuide.getBoundingClientRect(); var tagRect = tag.getBoundingClientRect(); tag.style.left = '' + (tagGuideRect.left + window.scrollX - tagRect.width - 60) + 'px'; tag.style.top = '' + (rect.top + window.scrollY) + 'px'; } var taggedElements = document.querySelectorAll('.postArticle-content'); for (var el of taggedElements) { //el.addEventListener('mouseover', onMouseOver, true); el.addEventListener('click', onMouseOver, true); } } function onLoad() { // Bind keys var main = document.querySelector('main[contenteditable="true"]'); main.addEventListener('keydown', onKeyDown, true); fixQuotes(); showPermalink(); } function waitForLoad() { var main = document.querySelector('main[contenteditable="true"]'); if (main) { onLoad(); console.log('[Medium: Markdown] Loaded'); } else { setTimeout(waitForLoad, 100); } } setTimeout(waitForLoad, 100); })();