Created
January 2, 2024 23:38
-
-
Save Lauloque/e457e163bd50b5e08f91965fced9eb2c to your computer and use it in GitHub Desktop.
kbd formatting function for blender.community
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 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 = "⎈ Ctrl"; | |
| break; | |
| case "alternate": | |
| case "alt": | |
| refined_markdown = "⎇ Alt"; | |
| break; | |
| case "shift": | |
| refined_markdown = "⇧ Shift"; | |
| break; | |
| case "tab": | |
| refined_markdown = "↹ Tab"; | |
| break; | |
| case "delete": | |
| case "del": | |
| refined_markdown = "⌦ Delete"; | |
| break; | |
| case "enter": | |
| case "return": | |
| refined_markdown = "⏎ Enter"; | |
| break; | |
| case "backspace": | |
| refined_markdown = "⟵ Backspace"; | |
| break; | |
| case "pageup": | |
| case "pgup": | |
| refined_markdown = "⇞ Page up"; | |
| break; | |
| case "pagedown": | |
| case "pgdn": | |
| refined_markdown = "⇟ Page down"; | |
| break; | |
| case "printscreen": | |
| refined_markdown = "⎙ Print Screen"; | |
| break; | |
| case "up": | |
| refined_markdown = "↑ Up arrow"; | |
| break; | |
| case "left": | |
| refined_markdown = "← Left arrow"; | |
| break; | |
| case "right": | |
| refined_markdown = "→ Right arrow"; | |
| break; | |
| case "down": | |
| refined_markdown = "↓ Down arrow"; | |
| break; | |
| case "caps": | |
| case "capslock": | |
| refined_markdown = "⇪ Caps Lock"; //maybe use ⇬ instead? | |
| break; | |
| case "win": | |
| case "windows": | |
| case "windowskey": | |
| case "winkey": | |
| refined_markdown = "🪟Win"; | |
| break; | |
| case "super": | |
| case "linux": | |
| case "linuxkey": | |
| case "tuxkey": | |
| refined_markdown = "⌘ Super"; | |
| break; | |
| case "meta": | |
| refined_markdown = "◆ Meta"; | |
| break; | |
| //mac thingies | |
| case "command": | |
| case "cmd": | |
| refined_markdown = "⌘ Cmd"; | |
| break; | |
| case "option": | |
| case "opt": | |
| refined_markdown = "⌥ 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); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To do:
answer templates insertion. Example: