Last active
June 12, 2018 14:00
-
-
Save GaurangTandon/860cbdef7355fa2978dc4bd3cb408981 to your computer and use it in GitHub Desktop.
Bold, italics, link, and custom shortcuts for comments in Stack Exchange
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Comment Keyboard shortcuts | |
// @version 0.1 | |
// @description Bold, italics, link, and custom shortcuts for comments in Stack Exchange | |
// @author Gaurang Tandon | |
// @match *://*.askubuntu.com/* | |
// @match *://*.mathoverflow.net/* | |
// @match *://*.serverfault.com/* | |
// @match *://*.stackapps.com/* | |
// @match *://*.stackexchange.com/* | |
// @match *://*.stackoverflow.com/* | |
// @match *://*.superuser.com/* | |
// @match *://chat.stackexchange.com/* | |
// @match *://chat.stackoverflow.com/* | |
// @exclude *://api.stackexchange.com/* | |
// @exclude *://blog.stackexchange.com/* | |
// @exclude *://blog.stackoverflow.com/* | |
// @exclude *://data.stackexchange.com/* | |
// @exclude *://elections.stackexchange.com/* | |
// @exclude *://openid.stackexchange.com/* | |
// @exclude *://stackexchange.com/* | |
// @grant none | |
// @history 0.1 - 9th June 2018 - Hello world! | |
// ==/UserScript== | |
/** BUGS: | |
* TODO: fix redundancy of insertTextWrapper and insertLink | |
*/ | |
(function() { | |
'use strict'; | |
/*NOTE: once you hit Enter and submit a comment, and then click "add comment" under the same post, the same textarea is again given to you unmodified as it was before*/ | |
// (Ctrl +) keycode: ["placeholder", "delimiter"] | |
// you can easily extend this with your own wrappers | |
var WRAPPERS = { | |
66: ["strong text", "**"], | |
// use underscore for italics instead of asterisks to prevent | |
// clashes with bold | |
73: ["emphasized text", "_"], | |
75: ["enter code here", "`"] | |
}; | |
function insertTextWrapper(commentBox, wrapper){ | |
/*--- Expected behavior: | |
When there is some text selected: (unwrap it if already wrapped) | |
"]text[" --> "**]text[**" | |
"**]text[**" --> "]text[" | |
"]**text**[" --> "**]**text**[**" | |
"**]**text**[**" --> "]**text**[" | |
When there is no text selected: | |
"][" --> "**placeholder text**" | |
"**][**" --> "" | |
Note that `]` and `[` denote the selected text here. | |
*/ | |
var selS = commentBox.selectionStart, | |
selE = commentBox.selectionEnd, | |
value = commentBox.value, | |
valBefore = value.substring(0, selS), | |
valMid = value.substring(selS, selE), | |
valAfter = value.substring(selE), | |
delimiter = wrapper[1], | |
delimLen = delimiter.length, | |
generatedWrapper, | |
// handle trailing spaces | |
trimmedSelection = valMid.match (/^(\s*)(\S?(?:.|\n|\r)*\S)(\s*)$/) || ["", "", "", ""]; | |
// determine if text is currently wrapped | |
if(valBefore.endsWith(delimiter) && valAfter.startsWith(delimiter)){ | |
commentBox.value = valBefore.substring(0, valBefore.length - delimLen) + valMid + valAfter.substring(delimLen); | |
commentBox.selectionStart = valBefore.length - delimLen; | |
commentBox.selectionEnd = (valBefore + valMid).length - delimLen; | |
commentBox.focus(); | |
}else{ | |
valBefore += trimmedSelection[1]; | |
valAfter = trimmedSelection[3] + valAfter; | |
valMid = trimmedSelection[2]; | |
generatedWrapper = delimiter + (valMid || wrapper[0]) + delimiter; | |
commentBox.value = valBefore + generatedWrapper + valAfter; | |
commentBox.selectionStart = valBefore.length + delimiter.length; | |
commentBox.selectionEnd = (valBefore + generatedWrapper).length - delimiter.length; | |
commentBox.focus(); | |
} | |
} | |
function insertLink(commentBox){ | |
var selS = commentBox.selectionStart, | |
selE = commentBox.selectionEnd, | |
value = commentBox.value, | |
valBefore = value.substring(0, selS), | |
valMid = value.substring(selS, selE), | |
valAfter = value.substring(selE), | |
placeholder = "enter link description here", | |
trimmedSelection = valMid.match (/^(\s*)(\S?(?:.|\n|\r)*\S)(\s*)$/) || ["", "", "", ""], | |
insertedMiddleText, | |
link = prompt("Insert Hyperlink http://example.com/"); | |
valBefore += trimmedSelection[1]; | |
valAfter = trimmedSelection[3] + valAfter; | |
valMid = trimmedSelection[2]; | |
if(!/^http/.test(link)) link = "http://" + link; | |
insertedMiddleText = valMid || placeholder | |
commentBox.value = valBefore + "[" + insertedMiddleText + "](" + link + ")" + valAfter; | |
commentBox.selectionStart = valBefore.length + 1; | |
commentBox.selectionEnd = (valBefore + insertedMiddleText).length + 1; | |
commentBox.focus(); | |
} | |
function attachHandlers(commentBox){ | |
commentBox.onkeydown = function handleKeyDown(event){ | |
var kC = event.keyCode; | |
if(!(event.ctrlKey || event.metaKey)) return true; | |
if(kC === 76){ // L | |
event.preventDefault(); | |
insertLink(commentBox); | |
return; | |
} | |
if(WRAPPERS[kC]) { | |
event.preventDefault(); | |
insertTextWrapper(commentBox, WRAPPERS[kC]); | |
} | |
}; | |
} | |
setInterval(function(){ | |
// first query for SE, second for chat | |
var commentBoxes = document.querySelectorAll(".js-comment-text-input:not(.key-shortcut-processed), textarea#input:not(.key-shortcut-processed)"), commentBox; | |
for(var i = 0, len = commentBoxes.length; i < len; i++){ | |
commentBox = commentBoxes[i]; | |
commentBox.classList.add("key-shortcut-processed"); | |
attachHandlers(commentBox); | |
} | |
}, 500); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment