2022-10-19 17:52:08 +03:00
|
|
|
// iframe parent
|
|
|
|
var parentDoc = window.parent.document
|
|
|
|
|
|
|
|
// check for mouse pointer locking support, not a requirement but improves the overall experience
|
|
|
|
var havePointerLock = 'pointerLockElement' in parentDoc ||
|
|
|
|
'mozPointerLockElement' in parentDoc ||
|
|
|
|
'webkitPointerLockElement' in parentDoc;
|
|
|
|
|
|
|
|
// the pointer locking exit function
|
|
|
|
parentDoc.exitPointerLock = parentDoc.exitPointerLock || parentDoc.mozExitPointerLock || parentDoc.webkitExitPointerLock;
|
|
|
|
|
2022-10-20 12:39:09 +03:00
|
|
|
// how far should the mouse travel for a step in pixel
|
|
|
|
var pixelPerStep = %%pixelPerStep%%;
|
2022-10-19 17:52:08 +03:00
|
|
|
// how many steps did the mouse move in as float
|
|
|
|
var movementDelta = 0.0;
|
|
|
|
// value when drag started
|
2022-10-20 13:03:52 +03:00
|
|
|
var lockedValue = 0.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
// minimum value from field
|
2022-10-20 13:03:52 +03:00
|
|
|
var lockedMin = 0.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
// maximum value from field
|
2022-10-20 13:03:52 +03:00
|
|
|
var lockedMax = 0.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
// how big should the field steps be
|
2022-10-20 13:03:52 +03:00
|
|
|
var lockedStep = 0.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
// the currently locked in field
|
|
|
|
var lockedField = null;
|
|
|
|
|
2022-10-20 12:39:09 +03:00
|
|
|
// lock box to just request pointer lock for one element
|
|
|
|
var lockBox = document.createElement("div");
|
|
|
|
lockBox.classList.add("lockbox");
|
|
|
|
parentDoc.body.appendChild(lockBox);
|
|
|
|
lockBox.requestPointerLock = lockBox.requestPointerLock || lockBox.mozRequestPointerLock || lockBox.webkitRequestPointerLock;
|
|
|
|
|
|
|
|
function Lock(field)
|
|
|
|
{
|
|
|
|
var rect = field.getBoundingClientRect();
|
|
|
|
lockBox.style.left = (rect.left-2.5)+"px";
|
|
|
|
lockBox.style.top = (rect.top-2.5)+"px";
|
|
|
|
|
|
|
|
lockBox.style.width = (rect.width+2.5)+"px";
|
|
|
|
lockBox.style.height = (rect.height+5)+"px";
|
|
|
|
|
|
|
|
lockBox.requestPointerLock();
|
|
|
|
}
|
|
|
|
|
|
|
|
function Unlock()
|
|
|
|
{
|
|
|
|
parentDoc.exitPointerLock();
|
|
|
|
lockBox.style.left = "0px";
|
|
|
|
lockBox.style.top = "0px";
|
|
|
|
|
|
|
|
lockBox.style.width = "0px";
|
|
|
|
lockBox.style.height = "0px";
|
|
|
|
lockedField.focus();
|
|
|
|
}
|
|
|
|
|
2022-10-19 17:52:08 +03:00
|
|
|
parentDoc.addEventListener('mousedown', (e) => {
|
|
|
|
// if middle is down
|
|
|
|
if(e.button === 1)
|
|
|
|
{
|
|
|
|
if(e.target.tagName === 'INPUT' && e.target.type === 'number')
|
|
|
|
{
|
|
|
|
e.preventDefault();
|
|
|
|
var field = e.target;
|
|
|
|
if(havePointerLock)
|
2022-10-20 12:39:09 +03:00
|
|
|
Lock(field);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
// save current field
|
|
|
|
lockedField = e.target;
|
|
|
|
// add class for styling
|
|
|
|
lockedField.classList.add("value-dragging");
|
|
|
|
// reset movement delta
|
|
|
|
movementDelta = 0.0;
|
|
|
|
// set to 0 if field is empty
|
|
|
|
if(lockedField.value === '')
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedField.value = 0.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
// save current field value
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedValue = parseFloat(lockedField.value);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
if(lockedField.min === '' || lockedField.min === '-Infinity')
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedMin = -99999999.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
else
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedMin = parseFloat(lockedField.min);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
if(lockedField.max === '' || lockedField.max === 'Infinity')
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedMax = 99999999.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
else
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedMax = parseFloat(lockedField.max);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
if(lockedField.step === '' || lockedField.step === 'Infinity')
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedStep = 1.0;
|
2022-10-19 17:52:08 +03:00
|
|
|
else
|
2022-10-20 13:03:52 +03:00
|
|
|
lockedStep = parseFloat(lockedField.step);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
// lock pointer if available
|
|
|
|
if(havePointerLock)
|
2022-10-20 12:39:09 +03:00
|
|
|
Lock(lockedField);
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
// add drag event
|
|
|
|
parentDoc.addEventListener("mousemove", onDrag, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-10-20 12:39:09 +03:00
|
|
|
function onDrag(e)
|
|
|
|
{
|
2022-10-19 17:52:08 +03:00
|
|
|
if(lockedField !== null)
|
|
|
|
{
|
|
|
|
// add movement to delta
|
|
|
|
movementDelta += e.movementX / pixelPerStep;
|
|
|
|
if(lockedField === NaN)
|
|
|
|
return;
|
|
|
|
// set new value
|
|
|
|
let value = lockedValue + Math.floor(Math.abs(movementDelta)) * lockedStep * Math.sign(movementDelta);
|
|
|
|
lockedField.focus();
|
|
|
|
lockedField.select();
|
|
|
|
parentDoc.execCommand('insertText', false /*no UI*/, Math.min(Math.max(value, lockedMin), lockedMax));
|
|
|
|
}
|
2022-10-20 12:39:09 +03:00
|
|
|
}
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
parentDoc.addEventListener('mouseup', (e) => {
|
|
|
|
// if mouse is up
|
|
|
|
if(e.button === 1)
|
|
|
|
{
|
|
|
|
// release pointer lock if available
|
|
|
|
if(havePointerLock)
|
2022-10-20 12:39:09 +03:00
|
|
|
Unlock();
|
2022-10-19 17:52:08 +03:00
|
|
|
|
|
|
|
if(lockedField !== null && lockedField !== NaN)
|
|
|
|
{
|
|
|
|
// stop drag event
|
|
|
|
parentDoc.removeEventListener("mousemove", onDrag, false);
|
|
|
|
// remove class for styling
|
|
|
|
lockedField.classList.remove("value-dragging");
|
|
|
|
// remove reference
|
|
|
|
lockedField = null;
|
|
|
|
}
|
|
|
|
}
|
2022-10-20 12:39:09 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// only execute once (even though multiple iframes exist)
|
|
|
|
if(!parentDoc.hasOwnProperty("dragableInitialized"))
|
|
|
|
{
|
|
|
|
var parentCSS =
|
|
|
|
`
|
|
|
|
/* Make input-instruction not block mouse events */
|
|
|
|
.input-instructions,.input-instructions > *{
|
|
|
|
pointer-events: none;
|
|
|
|
user-select: none;
|
|
|
|
-moz-user-select: none;
|
|
|
|
-khtml-user-select: none;
|
|
|
|
-webkit-user-select: none;
|
|
|
|
-o-user-select: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.lockbox {
|
|
|
|
background-color: transparent;
|
|
|
|
position: absolute;
|
|
|
|
pointer-events: none;
|
|
|
|
user-select: none;
|
|
|
|
-moz-user-select: none;
|
|
|
|
-khtml-user-select: none;
|
|
|
|
-webkit-user-select: none;
|
|
|
|
-o-user-select: none;
|
|
|
|
border-left: dotted 2px rgb(255,75,75);
|
|
|
|
border-top: dotted 2px rgb(255,75,75);
|
|
|
|
border-bottom: dotted 2px rgb(255,75,75);
|
|
|
|
border-right: dotted 1px rgba(255,75,75,0.2);
|
|
|
|
border-top-left-radius: 0.25rem;
|
|
|
|
border-bottom-left-radius: 0.25rem;
|
|
|
|
z-index: 1000;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
// get parent document head
|
|
|
|
var head = parentDoc.getElementsByTagName('head')[0];
|
|
|
|
// add style tag
|
|
|
|
var s = document.createElement('style');
|
|
|
|
// set type attribute
|
|
|
|
s.setAttribute('type', 'text/css');
|
|
|
|
// add css forwarded from python
|
|
|
|
if (s.styleSheet) { // IE
|
|
|
|
s.styleSheet.cssText = parentCSS;
|
|
|
|
} else { // the world
|
|
|
|
s.appendChild(document.createTextNode(parentCSS));
|
|
|
|
}
|
|
|
|
// add style to head
|
|
|
|
head.appendChild(s);
|
|
|
|
// set flag so this only runs once
|
|
|
|
parentDoc["dragableInitialized"] = true;
|
|
|
|
}
|
|
|
|
|