public
Last active

This is a userscript that adds shortcuts for adding <kbd> tags to posts. Designed for Stack Exchange sites.

  • Download Gist
Add_kbd_shortcut.user.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
// ==UserScript==
// @name StackExchange, Add kbd shortcut
// @namespace StackExchange
// @description Adds a button and a keyboard shortcut (Alt-K) to add <kbd> tags.
// @version 1.1
// @match http://*.askubuntu.com/*
// @match http://*.onstartups.com/*
// @match http://*.serverfault.com/*
// @match http://*.stackapps.com/*
// @match http://*.stackexchange.com/*
// @match http://*.stackoverflow.com/*
// @match http://*.superuser.com/*
// ==/UserScript==
 
function AddKbdShortcuts ($) {
$("textarea.wmd-input").each (AddKbdButtonAsNeeded);
 
//.on() not working right!!
$("textarea.wmd-input").live ("focus", AddKbdButtonAsNeeded);
$("textarea.wmd-input").live ("keydown", InsertKbdTagByKeypress);
$("li.wmd-kbd-button") .live ("click", InsertKbdTagByClick);
 
/*------------*/
function AddKbdButtonAsNeeded () {
var jThis = $(this);
if ( ! jThis.data ("hasKbdBttn") ) {
//--- Find the button bar and add our button.
var btnBar = jThis.prevAll ("div.wmd-button-bar");
if (btnBar.length) {
//--- The button bar takes a while to AJAX-in.
var bbListTimer = setInterval ( function() {
var bbList = btnBar.find ("ul.wmd-button-row");
if (bbList.length) {
clearInterval (bbListTimer);
bbList.append (
'<li class="wmd-button wmd-kbd-button" '
+ 'title="Keyboard tag &lt;kbd&gt; Alt+K" '
+ 'style="left: 380px;">'
+ '<span><kbd style="border: 0px;">kbd</kbd></span></li>'
);
jThis.data ("hasKbdBttn", true);
}
},
100
);
}
}
}
 
function InsertKbdTagByKeypress (zEvent) {
//--- On Alt-K, insert the <kbd> set. Ignore all other keys.
if (zEvent.altKey && zEvent.which == 75) {
InsertKbdTag (this);
return false;
}
return true;
}
 
function InsertKbdTagByClick (zEvent) {
//--- From the clicked button, find the matching textarea.
var targArea = $(this).parents ("div.wmd-button-bar")
.nextAll ("textarea.wmd-input");
 
InsertKbdTag (targArea[0]);
targArea.focus ();
try {
//--- This is a utility function that SE currently provides on its pages.
StackExchange.MarkdownEditor.refreshAllPreviews ();
}
catch (e) {
console.warn ("***Userscript error: refreshAllPreviews() is no longer defined!");
}
}
 
function InsertKbdTag (node) {
//--- Wrap selected text or insert at curser.
var tagLength = 5; // Tag is: "<kbd>"
var oldText = node.value || node.textContent;
var newText;
var iTargetStart = node.selectionStart;
var iTargetEnd = node.selectionEnd;
var selectedText = oldText.slice (iTargetStart, iTargetEnd);
var possWrappedTxt;
try {
//--- Lazyman's overrun checking...
possWrappedTxt = oldText.slice (
iTargetStart - tagLength,
iTargetEnd + tagLength + 1
);
}
catch (e) {
possWrappedTxt = "Text can't be wrapped, cause we overran the string.";
}
 
/*--- Is the current selection wrapped? If so, just unwrap it.
This works the same way as SE's bold, italic, code, etc...
"]text[" --> "<kbd>]text[</kbd>"
"<kbd>]text[</kbd>" --> "]text["
"]<kbd>text</kbd>[" --> "<kbd>]<kbd>text</kbd>[</kbd>"
 
Except that:
"][" --> "<kbd>][</kbd>"
"<kbd>][</kbd>" --> "]["
with no placeholder text.
Note that `]` and `[` denote the selected text here.
*/
if (possWrappedTxt &&
selectedText == possWrappedTxt.replace (/^<kbd>((?:.|\n|\r)*)<\/kbd>$/, "$1")
) {
iTargetStart -= tagLength;
iTargetEnd += tagLength + 1;
newText = oldText.slice (0, iTargetStart)
+ selectedText + oldText.slice (iTargetEnd)
;
iTargetEnd = iTargetStart + selectedText.length;
}
else {
/*--- Here we will wrap the selection in our tags, but there is one extra
condition. We don't want to wrap leading or trailing whitespace.
*/
var trimSelctd = selectedText.match (/^(\s*)(\S?(?:.|\n|\r)*\S)(\s*)$/)
|| ["", "", "", ""]
;
if (trimSelctd.length != 4) {
console.warn ("***Userscript error: unexpected failure of whitespace RE.");
}
else {
newText = trimSelctd[1] //-- Leading whitespace, if any.
+ '<kbd>' + trimSelctd[2] + '</kbd>'
+ trimSelctd[3] //-- Trailing whitespace, if any.
;
newText = oldText.slice (0, iTargetStart)
+ newText + oldText.slice (iTargetEnd)
;
iTargetStart += tagLength + trimSelctd[1].length;
iTargetEnd += tagLength - trimSelctd[3].length;
}
}
 
//console.log (newText);
node.value = newText;
//--- After using spelling corrector, this gets buggered, hence the multiple sets.
node.textContent = newText;
 
//--- Have to reset the selection, since we overwrote the text.
node.selectionStart = iTargetStart;
node.selectionEnd = iTargetEnd;
}
}
 
 
withPages_jQuery (AddKbdShortcuts);
 
 
function withPages_jQuery (NAMED_FunctionToRun) {
//--- Use named functions for clarity and debugging...
var funcText = NAMED_FunctionToRun.toString ();
var funcName = funcText.replace (/^function\s+(\w+)\s*\((.|\n|\r)+$/, "$1");
var script = document.createElement ("script");
script.textContent = funcText + "\n\n";
script.textContent += 'jQuery(document).ready( function () {' + funcName + '(jQuery);} );';
document.body.appendChild (script);
};

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.