Skip to content

Instantly share code, notes, and snippets.

@Lauloque
Created January 2, 2024 23:38
Show Gist options
  • Select an option

  • Save Lauloque/e457e163bd50b5e08f91965fced9eb2c to your computer and use it in GitHub Desktop.

Select an option

Save Lauloque/e457e163bd50b5e08f91965fced9eb2c to your computer and use it in GitHub Desktop.
kbd formatting function for blender.community
// ==UserScript==
// @name Keyboard formatting for Blender.Community
// @description Adds the ability to quickly insert keyboard formatting tags in Blender.Community posts and comments
// @include https://blender.community/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @version 7.0.1
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
// Credits of the original stackexchange script to CoDEmanX and iKlsR
// See https://blender.meta.stackexchange.com/q/388/599 for discussion
// Blender.Community adaptation made by Lauloque
//calls to GM functions must be outside of injected code, so put them here
function toggle_extra_markdown() {
console.log("checkbox click, was", GM_getValue("extra_markdown", 1))
if (GM_getValue("extra_markdown", 1) == 1) {
GM_setValue("extra_markdown", 0);
}
else {
GM_setValue("extra_markdown", 1);
}
}
function get_prefs() {
return GM_getValue("extra_markdown", 1);
}
//stuff which will be injected with jquery goes in main:
function main() {
var pref_extra_markdown = 0
console.log("running main!");
function startInjection() {
//define keyboard shortcut even handler (Ctrl+Y)
$(document).on('keydown', "textarea", function(e) {
if (e.ctrlKey && (e.which === 89)) {
// turns out SE silently binds Ctrl+Y to redo in addition to Ctrl+Shift+Z; needless to say, us both messing with the content at the same time causes havoc, so we stop SE.
// TODO: this doesn't always seem to work, possibly a race condition? May be best to bind to a different key.
e.stopImmediatePropagation();
insertKbdTag(this);
}
});
}
function insertKbdTag(txta) {
if (txta.selectionStart == null) return;
var start = txta.selectionStart;
var end = txta.selectionEnd;
var added = 0;
var chars = txta.value;
console.log("chars: " + chars);
//separate selection from rest of body
var pre = chars.slice(0, start);
var post = chars.slice(end);
if (start != end) {
var sel = chars.slice(start, end);
console.log("sel: " + sel);
sel = sel.match(/(?:\S+|\s)/g); //split string around whitespace without deleting whitespace, thanks to this SO post: http://stackoverflow.com/a/24504047/2730823
console.log("sel: " + sel);
//remove extra spaces and replace them with kbd markdown
//var lastElement = ""; //holds previous element
var wasSpace = 0; //tracks if last element was a space
var endSpaces = 0; //needed for special end cases
var endSpace = 0;
var refined_markdown = "";
for (var char = 0; char < sel.length; char++) {
console.log("element " + char + ": " + "'" + sel[char] + "'")
//if current this element is a space, check to see if it should be replaced with a kbd
if (sel[char] == " ") {
//if previous element was not a space, replace space with kbd
if (wasSpace != 1 && char != 0) {
sel.splice(char, 1, ']] [[');
//added += 10;
wasSpace = 1;
endSpace = char;
}
else {
//console.log("asdf42")
//console.log(sel.join(""))
sel.splice(char, 1); //remove extra space
//console.log(sel.join(""))
wasSpace = 1;
char--; //go back one element
}
}
else {
wasSpace = 0;
}
if (wasSpace == 1) {
endSpaces ++;
}
else {
endSpaces = 0;
}
//test if get_prefs is defined, and if it is test if GM_value "extra markdown" is 1. If get_prefs is not defined, use the non-persistent variable:
if (((typeof get_prefs === "function") ? get_prefs() : pref_extra_markdown) == 1 ) {
//console.log("element: " + sel[char])
switch(sel[char].toLowerCase()) {
case "control":
case "ctrl":
refined_markdown = "&#9096; Ctrl";
break;
case "alternate":
case "alt":
refined_markdown = "&#9095; Alt";
break;
case "shift":
refined_markdown = "&#8679; Shift";
break;
case "tab":
refined_markdown = "&#8633; Tab";
break;
case "delete":
case "del":
refined_markdown = "&#8998; Delete";
break;
case "enter":
case "return":
refined_markdown = "&#9166; Enter";
break;
case "backspace":
refined_markdown = "&#10229; Backspace";
break;
case "pageup":
case "pgup":
refined_markdown = "&#8670; Page up";
break;
case "pagedown":
case "pgdn":
refined_markdown = "&#8671; Page down";
break;
case "printscreen":
refined_markdown = "&#9113; Print Screen";
break;
case "up":
refined_markdown = "&#8593; Up arrow";
break;
case "left":
refined_markdown = "&#8592; Left arrow";
break;
case "right":
refined_markdown = "&#8594; Right arrow";
break;
case "down":
refined_markdown = "&#8595; Down arrow";
break;
case "caps":
case "capslock":
refined_markdown = "&#8682; Caps Lock"; //maybe use &#8684; instead?
break;
case "win":
case "windows":
case "windowskey":
case "winkey":
refined_markdown = "🪟Win";
break;
case "super":
case "linux":
case "linuxkey":
case "tuxkey":
refined_markdown = "&#8984; Super";
break;
case "meta":
refined_markdown = "&#9670; Meta";
break;
//mac thingies
case "command":
case "cmd":
refined_markdown = "&#8984; Cmd";
break;
case "option":
case "opt":
refined_markdown = "&#8997; Opt";
break;
//mouse things
case "wheel":
case "scrollwheel":
case "mousewheel":
case "mw":
refined_markdown = "Wheel 🖱️";
break;
case "mmb":
refined_markdown = "Middle 🖱️";
break;
case "lmb":
refined_markdown = "Left 🖱️";
break;
case "rmb":
refined_markdown = "Right 🖱️";
break;
}
console.log("refined_markdown: " + refined_markdown)
console.log("refined_markdown.length: " + refined_markdown.length)
if (refined_markdown.length > 0) {
//added += refined_markdown.length;
sel.splice(char, 1, refined_markdown);
refined_markdown = "";
}
}
}
//handle end case separatly; if there is more than 1 space at the end, the last array item is '</kbd><kbd>'
//that will result in an extra <kbd> pair, so remove it.
if (endSpaces > 0) {
sel.splice(endSpace, 1);
}
}
else { /*if there is no selection, assign sel to an array so that sel.join returns ""*/
var sel = ["",];
}
//put everything back together again
txta.value = pre + "[[" + sel.join("") + "]]" + post;
added = sel.join("").length + 11
//TODO, this is broken. Need to update cursor position calculation
txta.selectionStart = txta.selectionEnd = pre.length + ((start == end) ? 5 : added); //remove the selection and move
$(txta).focus();
updateMarkdownPreview(txta);
/*
// jQuery-way doesn't work :(
var evt = $.Event('keydown');
evt.which = 17;
evt.keyCode = 17; // Ctrl
$(txta).trigger(e);
// another failing attempt
$(txta).trigger({
type: "keydown",
which : 17
});
*/
}
//function to force update the live markdown render
function updateMarkdownPreview(element) {
var keyboardEvent = document.createEvent("KeyboardEvent");
var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
/*keyboardEvent[initMethod](
"keydown", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
window, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
17, // keyCodeArg : unsigned long the virtual key code, else 0
0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
);
element.dispatchEvent(keyboardEvent);*/
//horrible hack so undo after inserting kbd tags only removes kbd tags
//TODO not sure why this works, need to investigate at some point..
keyboardEvent[initMethod](
"keydown", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
document.defaultView, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
66, // keyCodeArg : unsigned long the virtual key code, else 0
0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
);
element.dispatchEvent(keyboardEvent);
keyboardEvent[initMethod](
"keydown", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
document.defaultView, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
8, // keyCodeArg : unsigned long the virtual key code, else 0
0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
);
element.dispatchEvent(keyboardEvent);
}
startInjection() //call initial startup function (bind keyboard shortcuts, etc.)
}
//get jquery on chrome, thanks to this SO post: http://stackoverflow.com/a/12751531/2730823
if (typeof jQuery === "function") {
console.log ("Running with local copy of jQuery!");
main (jQuery);
}
else {
console.log ("fetching jQuery from some 3rd-party server.");
add_jQuery (main, "1.7.2");
}
function add_jQuery (callbackFn, jqVersion) {
var jqVersion = jqVersion || "1.7.2";
var D = document;
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
var scriptNode = D.createElement ('script');
scriptNode.src = 'http://ajax.googleapis.com/ajax/libs/jquery/'
+ jqVersion
+ '/jquery.min.js'
;
scriptNode.addEventListener ("load", function () {
var scriptNode = D.createElement ("script");
scriptNode.textContent =
'var gm_jQuery = jQuery.noConflict (true);\n'
+ '(' + callbackFn.toString () + ')(gm_jQuery);'
;
targ.appendChild (scriptNode);
}, false);
targ.appendChild (scriptNode);
}
@Lauloque
Copy link
Author

Lauloque commented Mar 26, 2024

To do:

answer templates insertion. Example:

Polishing one request, sharing and upvoting it to maximize its visibility would give it more chances to be seen and adopted by devs than making dozens of scattered posts that quickly get drowned in the pool of other proposals.

Srouce: Deep Compositing Export ⁠— Right-Click Select

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment