/* autogenerated output of all executables in the /scouting/executables folder */ var executables = {} //climbHighlight.js executables["climbHighlight"] = { execute(button, layers, args) { const otherClimbButtons = layers.flat().filter(x => x.executables.find(e => e.type == "climbHighlight")); console.log(otherClimbButtons) for (let otherButton of otherClimbButtons) { otherButton.element.classList.remove("highlight") } button.element.classList.add("highlight") }, async reverse(button, layers, args) { //find the current climb position by traversing the action queue backwards let highlightableButtons = {}; for (let layerButton of layers.flat()) { if (layerButton.executables.find(e => e.type == "climbHighlight")) //if its highlightable highlightableButtons[layerButton.id] = layerButton //add its id } let oldHighlightId = [...actionQueue].reverse().find(x=>x && x.id in highlightableButtons).id; //re add highlights button.element.classList.remove("highlight"); highlightableButtons[oldHighlightId].element.classList.add("highlight"); } } //conditionalLayer.js /** * Shows another layer on button press * @param fromLayer the layer number the executable is transitioning from (normally the layer which contains the button) * @param toLayer the layer which the executable is transitioning to (the layer that will be shown). */ executables["conditionalLayerUndo"] = { execute(button,layers,fromLayer,toLayer,alwaysRender,conditionalRender) { for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } console.log("CONDITIONAL LAYER(UNDO) --------------------------------------") console.log("variables"); console.log(variables) var renderedButtons = [] for (let button of layers[toLayer]) { var targetVariables = []; var targetValues = []; var thingsToCheck = { } for(let [variable,valueData] of Object.entries(conditionalRender)){ for(let [value,idList] of Object.entries(valueData)) { if(idList.includes(button.id)){ if(thingsToCheck[variable]){ thingsToCheck[variable].push(value) } else { thingsToCheck[variable] = [value] } } } } var display = false; for(let [variable,values] of Object.entries(thingsToCheck)){ if(values.includes(variables[variable].current)){ display = true } } if(alwaysRender.includes(button.id) || (display)){ button.element.style.display = "flex" renderedButtons.push(button) } } previousLayers.push(renderedButtons) }, reverse(button,layers,fromLayer,toLayer,alwaysRender,conditionalRender) { console.log("undoing conditional layer") for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } previousLayers.pop(); if(previousLayers.length>1){previousLayers.pop();} if(previousLayers.length-1 > 0){ for (let button of previousLayers[previousLayers.length-1]) { button.element.style.display = "flex" console.log(`displaying ${button.id}`) } } } } //conditionalLayerOnUndo.js /** * Shows another layer on button press * @param fromLayer the layer number the executable is transitioning from (normally the layer which contains the button) * @param toLayer the layer which the executable is transitioning to (the layer that will be shown). */ executables["conditionalLayer"] = { execute(button,layers,fromLayer,toLayer,alwaysRender,conditionalRender) { for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } console.log("CONDITIONAL LAYER --------------------------------------") console.log("variables"); console.log(variables) var renderedButtons = [] for (let button of layers[toLayer]) { var targetVariables = []; var targetValues = []; var thingsToCheck = { } for(let [variable,valueData] of Object.entries(conditionalRender)){ for(let [value,idList] of Object.entries(valueData)) { if(idList.includes(button.id)){ if(thingsToCheck[variable]){ thingsToCheck[variable].push(value) } else { thingsToCheck[variable] = [value] } } } } var display = false; for(let [variable,values] of Object.entries(thingsToCheck)){ if(values.includes(variables[variable].current)){ display = true } } if(alwaysRender.includes(button.id) || (display)){ button.element.style.display = "flex" renderedButtons.push(button) } } previousLayers.push(renderedButtons) }, reverse(button,layers,fromLayer,toLayer,alwaysRender,conditionalRender) { console.log("undoing conditional layer") for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } previousLayers.pop(); if(previousLayers.length>1){previousLayers.pop();} if(previousLayers.length-1 > 0){ for (let button of previousLayers[previousLayers.length-1]) { button.element.style.display = "flex" console.log(`displaying ${button.id}`) } } } } //constantPosition.js executables["constantPosition"] = { execute(button, layers,position) { //add the constant position to the action if (!actionQueue[actionQueue.length - 1].other) actionQueue[actionQueue.length - 1].other = {} actionQueue[actionQueue.length - 1].other.pos = position; }, reverse(button, layers, args) { //nothing to undo } } //exampleExecutable.js executables["example"] = { execute(button, layers, args) { //when the button is pressed, do this }, reverse(button, layers, args) { //when the button is undone, do this. This should undo EVERYTHING done by execute } } //flashBorder.js executables["flashBorder"] = { execute(button, layers, args) { //when the button is pressed, do this }, reverse(button, layers,args) { //when the button is undone, do this. This should undo EVERYTHING done by execute } } //hide.js /** * Hides the button on execute */ executables["hide"] = { execute(button) { //when the button is pressed, do this button.element.style.display = "none" }, reverse(button) { //when the button is undone, do this. This should undo EVERYTHING done by execute button.element.style.display = "flex" } } //layer.js /** * Shows another layer on button press * @param fromLayer the layer number the executable is transitioning from (normally the layer which contains the button) * @param toLayer the layer which the executable is transitioning to (the layer that will be shown). */ executables["layer"] = { execute(button,layers,fromLayer,toLayer) { for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } var renderedButtons = [] for (let button of layers[toLayer]) { button.element.style.display = "flex"; renderedButtons.push(button) } previousLayers.push(renderedButtons) }, reverse(button,layers,fromLayer,toLayer) { for (let button of layers.flat()) { //hide all buttons button.element.style.display = "none" } previousLayers.pop(); previousLayers.pop(); console.log(previousLayers) for (let button of previousLayers[previousLayers.length-1]) { button.element.style.display = "flex" } } } //multiplier.js executables["multiplier"] = { execute(button, layers, numActions) { if (button.type != "action") { console.warn("The 'multiplier' executable should only be used with 'action' buttons! Using it with buttons of other types can lead to unexpected results.") } //add numActions-1 actions to the action queue for (let i = 0; i < numActions - 1; i++) { actionQueue.push({ "id": button.id, "ts": actionQueue[actionQueue.length - 1].ts //get the time from the last action (the one created by the initial button press) }); } }, reverse(button, layers, numActions) { //add numActions-1 actions to the action queue for (let i = 0; i < numActions - 1; i++) { actionQueue.pop(); } } } //position.js /* * when the button is pressed, this executable collects position data from the user using a field map (src/scouting/public/img/field.png). * That data is then attached to the action in the "other.pos" field as percentages of an axis length (eg. action.other.pos = {x:0,y:0}) */ let positionConfig = { POSITION_LOCK_DELAY_MS: 1000, LOCK_BORDER_COLOR: "#00ffa5" } let lockedPosition; let lockedTime; executables["position"] = { execute(button, layers) { //position lock check if (lockedTime + positionConfig.POSITION_LOCK_DELAY_MS > Date.now()) { // if there's a position in lockedPosition, put it in the action. if (!actionQueue[actionQueue.length - 1].other) actionQueue[actionQueue.length - 1].other = {} actionQueue[actionQueue.length - 1].other.pos = lockedPosition; //set the border color and position lock time setAllButtonBorders(layers,positionConfig.LOCK_BORDER_COLOR); setTimeout(() => { if (lockedTime + positionConfig.POSITION_LOCK_DELAY_MS <= Date.now() + 10) setAllButtonBorders(layers,"transparent"); },positionConfig.POSITION_LOCK_DELAY_MS) lockedTime = Date.now(); return; } //when the button is pressed, do this const positionContainer = document.createElement("div"); positionContainer.style.cssText = ` width: 100vw; height: 100vh; position: absolute; top: 0; left: 0; display: flex; justify-content: center; align-items: center; background-color: white; ` const positionImage = new Image(); positionImage.src = "/img/field.svg"; positionImage.style.cssText = ` width: 100%; height: 100%; object-fit: contain; background-color: black; ` positionContainer.appendChild(positionImage); document.body.appendChild(positionContainer); positionImage.addEventListener("click", (e) => { /* position gathering */ //find image width/height and margin offsets let aspectRatio = positionImage.naturalWidth/positionImage.naturalHeight; let width = positionImage.height * aspectRatio; let height = positionImage.height; if (width > positionImage.width) { width = positionImage.width; height = positionImage.width / aspectRatio; } let marginX = (window.innerWidth - width) / 2; let marginY = (window.innerHeight - height) / 2; //find click/tap coordinates in terms of % of x and % of y let x = (e.offsetX - marginX) / width * 100; let y = (e.offsetY - marginY) / height * 100; //make x and y an integer between 0 and 100 x = Math.round(Math.max(Math.min(x,100),0)); y = Math.round(Math.max(Math.min(y,100),0)); //add the pos to the last action of the action queue (SHOULD be the action from the button that triggered this) if (!actionQueue[actionQueue.length - 1].other) actionQueue[actionQueue.length - 1].other = {} let pos = actionQueue[actionQueue.length - 1].other.pos = {x,y}; /* position lock */ if (positionConfig.POSITION_LOCK_DELAY_MS != 0) { //position lock is enabled, lockedTime = Date.now(); lockedPosition = pos; setAllButtonBorders(layers,positionConfig.LOCK_BORDER_COLOR); setTimeout(() => { if (lockedTime + positionConfig.POSITION_LOCK_DELAY_MS <= Date.now() + 10) setAllButtonBorders(layers,"transparent"); },positionConfig.POSITION_LOCK_DELAY_MS) } //remove the position image + container from DOM. document.body.removeChild(positionContainer); }) }, reverse(button, layers) { //nothing to do on reverse, but the function needs to be there } } function setAllButtonBorders(layers,color) { for (let button of layers.flat()) { if (button.executables.filter(x=>x.type=="position").length > 0) { //it has a position executable button.element.style.border = `0.5vw solid ${color}`; } } } //setVariable.js executables["setVariable"] = { execute(button, layers,name, value) { console.log("SET VARIABLE --------------------------------------") if(!variables[name]){ variables[name] = { "current":value, "previous":[] } } else { variables[name].previous.push(variables[name].current); variables[name].current = value; } console.log(variables) }, reverse(button, layers,name, value) { variables[name].current = variables[name].previous.pop() console.log(`reversing ${name} to ${variables[name].current}`) } }