Last active
May 5, 2024 12:41
-
-
Save folknor/35d406aa846a29a1e2bc0e0e5d0da4e0 to your computer and use it in GitHub Desktop.
Violentmonkey Script for KLE
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 KLE Floating Window | |
// @namespace folknor.KLE | |
// @version 1.2.2 | |
// @author folk | |
// @description Quality of life fixes for KLE. | |
// @grant none | |
// @match *://www.keyboard-layout-editor.com/* | |
// @run-at document-idle | |
// @inject-into page | |
// @downloadURL https://gist.githubusercontent.com/folknor/35d406aa846a29a1e2bc0e0e5d0da4e0/raw/vm-kle.js | |
// @updateURL https://gist.githubusercontent.com/folknor/35d406aa846a29a1e2bc0e0e5d0da4e0/raw/vm-kle.js | |
// ==/UserScript== | |
const floatingWindow = document.createElement('div'); | |
floatingWindow.style.position = 'fixed'; | |
floatingWindow.style.top = '50px'; | |
floatingWindow.style.left = '50px'; | |
floatingWindow.style.width = '650px'; | |
floatingWindow.style.height = '580px'; | |
floatingWindow.style.background = 'white'; | |
floatingWindow.style.border = '4px solid black'; | |
floatingWindow.style.zIndex = '1000'; | |
floatingWindow.style.overflow = 'hidden'; | |
const dragHandle = document.createElement('div'); | |
dragHandle.style.height = '12px'; | |
dragHandle.style.background = 'gray'; | |
dragHandle.style.cursor = 'move'; | |
dragHandle.style.zIndex = '1600'; | |
floatingWindow.appendChild(dragHandle); | |
const resizeHandle = document.createElement('div'); | |
resizeHandle.style.width = '0'; | |
resizeHandle.style.height = '0'; | |
resizeHandle.style.borderLeft = '8px solid transparent'; | |
resizeHandle.style.borderRight = '8px solid transparent'; | |
resizeHandle.style.borderBottom = '8px solid black'; | |
resizeHandle.style.cursor = 'nwse-resize'; | |
resizeHandle.style.position = 'absolute'; | |
resizeHandle.style.bottom = '-2px'; | |
resizeHandle.style.right = '-6px'; | |
resizeHandle.style.transform = 'rotate(135deg)'; | |
resizeHandle.style.zIndex = '1600'; | |
floatingWindow.appendChild(resizeHandle); | |
// Move the stuff | |
const element1 = document.querySelector('html.ng-scope body.ng-scope div#wrap div#body_all div.body ul.nav.nav-tabs'); | |
const element2 = document.querySelector('html.ng-scope body.ng-scope div#wrap div#body_all div.body div#tab-content.col-md-12.col-lg-12.row'); | |
const element3 = document.querySelector('html.ng-scope body.ng-scope div#wrap div#body_all div.body div.row'); | |
floatingWindow.appendChild(element1); | |
floatingWindow.appendChild(element2); | |
floatingWindow.appendChild(element3); | |
setTimeout(function() { | |
// Remove some CSS classes from the key properties form to make it jump around less | |
const keyProps = document.querySelector('div#properties form'); | |
keyProps.classList.remove("col-sm-8"); | |
keyProps.classList.remove("col-md-5"); | |
keyProps.classList.remove("col-lg-5"); | |
keyProps.classList.add("col"); | |
// Change to nav pills | |
let navEls = document.querySelectorAll("html.ng-scope body.ng-scope div ul.nav.nav-tabs"); | |
navEls.forEach(el => { | |
el.classList.remove("nav-tabs"); | |
el.classList.add("nav-pills"); | |
el.classList.add("nav-justified"); | |
el.querySelectorAll("a").forEach(anchor => { | |
anchor.style.paddingTop = "6px"; | |
anchor.style.paddingBottom = "6px"; | |
anchor.style.paddingLeft = "8px"; | |
anchor.style.paddingRight = "8px"; | |
}) | |
}); | |
let tabContent = document.getElementById("tab-content"); | |
tabContent.style.borderBottom = "none"; | |
tabContent.style.borderRight = "none"; | |
tabContent.style.borderLeft = "none"; | |
tabContent.style.paddingBottom = "0px"; | |
}, 500); | |
document.body.appendChild(floatingWindow); | |
function isElementVisible(elm) { | |
const rect = elm.getBoundingClientRect(); | |
return rect.top >= 0 && rect.left >= 0 && | |
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && | |
rect.right <= (window.innerWidth || document.documentElement.clientWidth); | |
} | |
let isDragging = false; | |
let offsetX, offsetY; | |
// Make sure the window is moved back if moved outside the bounds gg | |
setInterval(() => { | |
const dragHandleHidden = !isElementVisible(dragHandle); | |
if (dragHandleHidden) { | |
const rect = dragHandle.getBoundingClientRect(); | |
const windowHeight = window.innerHeight || document.documentElement.clientHeight; | |
const windowWidth = window.innerWidth || document.documentElement.clientWidth; | |
if (rect.bottom < 0 || rect.top > windowHeight || rect.right < 0 || rect.left > windowWidth) { | |
floatingWindow.style.left = `${Math.max(0, Math.min(windowWidth - floatingWindow.offsetWidth, parseFloat(floatingWindow.style.left)))}px`; | |
floatingWindow.style.top = `${Math.max(0, Math.min(windowHeight - floatingWindow.offsetHeight, parseFloat(floatingWindow.style.top)))}px`; | |
} | |
} | |
}, 1000); | |
dragHandle.addEventListener('mousedown', (e) => { | |
isDragging = true; | |
offsetX = e.clientX - floatingWindow.getBoundingClientRect().left; | |
offsetY = e.clientY - floatingWindow.getBoundingClientRect().top; | |
}); | |
document.addEventListener('mousemove', (e) => { | |
if (isDragging) { | |
floatingWindow.style.left = `${e.clientX - offsetX}px`; | |
floatingWindow.style.top = `${e.clientY - offsetY}px`; | |
} | |
}); | |
document.addEventListener('mouseup', () => { | |
isDragging = false; | |
}); | |
let isResizing = false; | |
resizeHandle.addEventListener('mousedown', (e) => { | |
isResizing = true; | |
const rect = floatingWindow.getBoundingClientRect(); | |
offsetX = e.clientX - rect.right; | |
offsetY = e.clientY - rect.bottom; | |
}); | |
document.addEventListener('mousemove', (e) => { | |
if (isResizing) { | |
floatingWindow.style.width = `${e.clientX - floatingWindow.getBoundingClientRect().left + offsetX}px`; | |
floatingWindow.style.height = `${e.clientY - floatingWindow.getBoundingClientRect().top + offsetY}px`; | |
} | |
}); | |
document.addEventListener('mouseup', () => { | |
isResizing = false; | |
}); | |
document.addEventListener('keyup', function(event) { | |
if (event.key === 'Enter') { | |
var num = -1; | |
try { | |
num = parseInt(document.querySelector('.key.selected .keylabels').firstElementChild.className.match(/\d+/)[0]); | |
} catch (err) { | |
// noop | |
} | |
if (num == -1 || typeof num === 'undefined') { | |
num = 0; | |
} | |
const inputBox = document.getElementById(`labeleditor${num}`); | |
if (inputBox) { | |
event.stopPropagation(); | |
event.stopImmediatePropagation(); | |
// If we have focus already, then select the next or previous key | |
if (document.activeElement && document.activeElement == inputBox) { | |
var ev; | |
if (event.shiftKey) { | |
ev = new KeyboardEvent('keydown', { | |
key: 'j', | |
keyCode: 74, | |
bubbles: true | |
}); | |
} else { | |
ev = new KeyboardEvent('keydown', { | |
key: 'k', | |
keyCode: 75, | |
bubbles: true | |
}); | |
} | |
document.querySelector('.key.selected').dispatchEvent(ev); | |
} else { | |
inputBox.setSelectionRange(0, inputBox.value.length) | |
inputBox.focus(); | |
} | |
} | |
} | |
}); |
v1.2.2 20240505 14:30 CET
- Changed a few CSS styles so that things look a bit better
- Window will now move itself back into the viewport if the drag handle ends up outside the viewport. This is just checked every 1 second.
- Resize handle is now always above the other content, so you can click it
- While a key is selected (red outline) in the KLE, pressing Enter will now select all text and focus input to the first legend input box that has any content.
- Enter: If no legend is set in any of the 12 boxes, it will put focus to the top left legend.
- Enter: While your keyboard focus is in one of the legend input boxes, if you hit Enter it will jump to the next legend or the next key in the KLE
- Unless Shift is held, in which case it will jump to the previous key in the KLE
- This might seen difficult to understand but to me with initial testing it feels quite intuitive
v1.2 20240427 19:36 CET
- Attempt to make the script auto update in violentmonkey
v1.1 20240427 19:26 CET
- Redesigned resize handle slightly
- Fixed color pickers were below the "window"
- Resizing the window doesn't instantly change the size so much, but still a little lulz
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Install instructions
https://gist.githubusercontent.com/folknor/35d406aa846a29a1e2bc0e0e5d0da4e0/raw/vm-kle.js
into the violentmonkey input boxThen any time you open a KLE this script will run