Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.watcherExclude": {
"**/target": true
}
}
1 change: 1 addition & 0 deletions data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

9 changes: 9 additions & 0 deletions debug.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[2026-01-28 02:55:39] submit.php hit
[2026-01-28 02:55:39] CWD=C:\Users\Matthew\Desktop\Scouting2026\5492_Scouting_2026
[2026-01-28 02:55:39] __DIR__=C:\Users\Matthew\Desktop\Scouting2026\5492_Scouting_2026
[2026-01-28 02:55:39] RAW_LEN=162
[2026-01-28 02:55:39] RAW=data=mhl%092026ilch%09qm%091%09r1%091%09%5B%5D%09%5B%5D%090%090%09x%090%090%090%09%5B%5D%090%090%090%090%090%090%09x%09x%09x%093%090%090%090%090%090%090%090%09%09
[2026-01-28 02:55:39] FIELDS_COUNT=1
[2026-01-28 02:55:39] Not enough fields to rearrange
[2026-01-28 02:55:39] WRITE_PATH=C:\Users\Matthew\Desktop\Scouting2026\5492_Scouting_2026\data.txt
[2026-01-28 02:55:39] WRITE_BYTES=163
460 changes: 357 additions & 103 deletions index.html

Large diffs are not rendered by default.

236 changes: 236 additions & 0 deletions indexold.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, maximum-scale=1.0">
<title>Scouting PASS</title>
<link rel="shortcut icon" href="favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="favicon.ico">
<script src="resources/js/easy.qrcode.min.js"></script>
<script src="resources/js/TBAInterface.js"></script>
<script src="resources/js/googleSheets.js"></script>
<script src="resources/js/scoutingPASS.js"></script>
<script src="2026/rebuilt_config.js"></script>
<link rel="stylesheet" href="resources/css/scoutingPASS.css">
</head>

<body>
<form id="scoutingForm" onsubmit="return false" name="scoutingForm">
<div id="main-panel-holder">
<div id="prematch" class="main-panel" style="background-color: black;">
<h1 id="prematchHeader1" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">N</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting PASS</h1>
<h2 id="prematchHeader2">pre-match</h2>
<p class="match-label"><input type="button" value="Next" id="nextButton1" onclick="swipePage(1)"></p>
<table id="prematch_table" style="font: Roboto">
<!-- ###PRE-MATCH-COMPONENTS###-->
</table>
<p class="match-label"><input type="button" value="Next" id="nextButton2" onclick="swipePage(1)"></p>
</div>

<div id="auton" class="main-panel" style="background-color: rgb(123, 168, 184);">
<h1 id="autonHeader1" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">n</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting PASS</h1>
<h2 id="autonHeader2">Auton</h2>
<p class="match-label"><input type="button" value="Prev" id="prevButton1" onclick="swipePage(-1)"><input type="button" value="Next" id="nextButton3" onclick="swipePage(1)"></p>
<table id="auton_table">
<!-- ###AUTON-COMPONENTS###-->
</table>
<p class="match-label"><input type="button" value="Prev" id="prevButton2" onclick="swipePage(-1)"> <input type="button" value="Next" id="nextButton4" onclick="swipePage(1)"></p>
</div>

<div id="teleop" class="main-panel" style="background-color: rgb(175, 207, 163);">
<h1 id="teleopHeader1" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">n</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting PASS</h1>
<h2 id="teleopHeader2" >Teleop</h2>
<p class="match-label"><input type="button" value="Prev" id="prevButton3" onclick="swipePage(-1)"><input type="button" value="Next" id="nextButton5" onclick="swipePage(1)"></p>
<table id="teleop_table">
<!-- ###TELEOP-COMPONENTS###-->
</table>
<p class="match-label"><input type="button" value="Prev" id="prevButton4" onclick="swipePage(-1)"> <input type="button" value="Next" id="nextButton6" onclick="swipePage(1)"></p>
</div>

<div id="endgame" class="main-panel" style="background-color: rgb(198, 186, 222);">
<h1 id="endgameHeader1" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">n</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting PASS</h1>
<h2 id="endgameHeader2">Endgame</h2>
<p class="match-label"><input type="button" value="Prev" id="prevButton5" onclick="swipePage(-1)"><input type="button" value="Next" id="nextButton7" onclick="swipePage(1)"></p>
<table id="endgame_table">
<!-- ###ENDGAME-COMPONENTS###-->
</table>
<p class="match-label"><input type="button" value="Prev" id="prevButton6" onclick="swipePage(-1)"> <input type="button" value="Next" id="nextButton8" onclick="swipePage(1)"></p>
</div>

<div id="post-match" class="main-panel" style="background-color: rgb(89, 134, 168);">
<h1 id="postmatchHeader" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">n</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting PASS</h1>
<h2>Miscellaneous</h2>
<p class="match-label"><input type="button" value="Prev" id="prevButton7" onclick="swipePage(-1)"><input type="button" value="Next" id="nextButton9" onclick="swipePage(1)"></p>
<table id="postmatch_table">
<!-- ###POST-MATCH-COMPONENTS###-->
</table>
<p class="match-label"><input type="button" value="Prev" id="prevButton8" onclick="swipePage(-1)"> <input type="button" value="Next" id="nextButton10" onclick="swipePage(1)"></p>
</div>

<div id="qr-code" class="main-panel" style="background-color: white;">
<h1 id="qrHeader1" class="page_title"><span class="odd">P</span><span class="even">W</span><span class="odd">n</span><span class="even">A</span><span class="odd">G</span><span class="even">E</span><br>Scouting 2026</h1>
<h2 id="qrHeader2">Generate QR Code</h2>
<p class="match-label"><input type="button" value="Prev" id="prevButton9" onclick="swipePage(-1)"></p>
<p id="qr-info"><span id="display_qr-info" style="border: none; text-align: center;"></span></p>
<script>
window.goatcounter = { path: function(p) { return location.host + p }}
</script>
<script data-goatcounter="https://scoutingpass.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
<table id="qr-table"><tr><td width="5%">&nbsp;</td><td width="90%">
<div id="qrcode" style="text-align:center">
<script>
// Create QRCode Object
qr = new QRCode(document.getElementById("qrcode"), options)
</script>
</div>
</td><td width="5%">&nbsp;</td></tr>
<tr><td width="5%">&nbsp;</td><td width="90%">
<div>
<p id="data" style="text-align:center"></p>
</div>
</td><td width="5%">&nbsp;</td></tr>
</table>
<p></p>
<p class="match-label"><input type="button" value="Display Data" id="displayButton" onclick="displayData()"><input type="button" value="Copy Data" id="copyButton" onclick="copyData()"></p>
<div id="submitButton">
<button id="submit" type="button" class="submitForm" onclick="submitData()">
Send Data to data.txt
</button>
</div>
<div id="clearButton">
<button type="button" class="clearForm" onclick="clearForm()">Clear Form</button>
</div>
<br>
</div>
</div>
</form>
</body>
<script>
(() => {
const CSV_URL = "teams.csv"; // <-- change if needed

let scheduleMap = null; // { "1": { "r1": {team:"5492", name:"Robo..."}, ... }, ... }

function parseCSVLine(line) {
const out = [];
let cur = "";
let inQuotes = false;

for (let i = 0; i < line.length; i++) {
const ch = line[i];
if (ch === '"') {
if (inQuotes && line[i + 1] === '"') { cur += '"'; i++; }
else { inQuotes = !inQuotes; }
} else if (ch === "," && !inQuotes) {
out.push(cur); cur = "";
} else {
cur += ch;
}
}
out.push(cur);
return out.map(s => s.trim());
}

async function loadSchedule() {
const resp = await fetch(CSV_URL, { cache: "no-store" });
if (!resp.ok) throw new Error(`Failed to fetch ${CSV_URL}: HTTP ${resp.status}`);

const text = await resp.text();
const lines = text.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
if (lines.length < 2) throw new Error("CSV has no data rows");

const map = {};
// skip header row
for (let i = 1; i < lines.length; i++) {
const cols = parseCSVLine(lines[i]);
if (cols.length < 3) continue;

const match = String(cols[0]);
const robot = String(cols[1]).toLowerCase();
const team = String(cols[2]);
const name = cols[3] ? String(cols[3]) : "";

if (!map[match]) map[match] = {};
map[match][robot] = { team, name };
}

scheduleMap = map;
console.log("Loaded local schedule:", scheduleMap);
}

function getSelectedRobot() {
const checked = document.querySelector('input[name="r"]:checked');
return checked ? checked.value.toLowerCase() : "";
}

function getMatchNumber() {
const m = document.getElementById("input_m");
return m ? String(m.value).trim() : "";
}

function setTeamNumber(teamNumber) {
const teamInput = document.getElementById("input_t");
if (!teamInput) return;

teamInput.value = teamNumber;

// fire events so any other code listening updates too
teamInput.dispatchEvent(new Event("input", { bubbles: true }));
teamInput.dispatchEvent(new Event("change", { bubbles: true }));

// optional: if your scoutingPASS.js has onTeamnameChange, call it
if (typeof window.onTeamnameChange === "function") {
try { window.onTeamnameChange(); } catch (e) {}
}
}

function autofillTeam() {
if (!scheduleMap) return;

const match = getMatchNumber();
const robot = getSelectedRobot();
if (!match || !robot) return;

const entry = scheduleMap[match]?.[robot];
if (!entry || !entry.team) return;

setTeamNumber(entry.team);
}

function attachWatchers() {
// match number field
const matchEl = document.getElementById("input_m");
if (matchEl) {
matchEl.addEventListener("input", autofillTeam);
matchEl.addEventListener("change", autofillTeam);
}

// robot radios (r1/r2/... b3)
document.addEventListener("change", (e) => {
const t = e.target;
if (t && t.matches && t.matches('input[name="r"]')) {
autofillTeam();
}
});

// run once in case defaults already selected
autofillTeam();
}

// Wait until the whole page + your other scripts have built the form from config
window.addEventListener("load", async () => {
try {
await loadSchedule();
} catch (e) {
console.log("Could not load local schedule CSV:", e.message);
return;
}
attachWatchers();
});
})();
</script>

</html>




47 changes: 45 additions & 2 deletions resources/js/scoutingPASS.js
Original file line number Diff line number Diff line change
Expand Up @@ -831,10 +831,13 @@ function configure() {
idx = addElement(pmt, idx, element);
});

if (!enableGoogleSheets) {
document.getElementById("submit").style.display = "none";
// We still want "submit" visible for saving to data.txt even if Google Sheets is off.
// Only hide it if the button doesn't exist for some reason.
if (!document.getElementById("submit")) {
console.log("No submit button found in HTML.");
}


return 0
}

Expand Down Expand Up @@ -1467,6 +1470,46 @@ function copyData(){
navigator.clipboard.writeText(getData(dataFormat));
document.getElementById('copyButton').setAttribute('value','Copied');
}
async function submitData() {
// If you want the same "required fields" behavior before saving:
if (!pitScouting) {
if (validateData() == false) {
return false;
}
}

const payload = getData(dataFormat);

// OPTIONAL: timestamp line prefix (uncomment if you want it)
// const payload = new Date().toISOString() + "\t" + getData(dataFormat);

try {
// This endpoint must exist on your server and append to data.txt
const resp = await fetch("submit.php", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" },
body: "data=" + encodeURIComponent(payload)
});

const text = await resp.text();

if (!resp.ok) {
alert("Save failed: " + text);
return false;
}

// Success UI feedback
alert("Saved to data.txt");
// Optionally clear the form after saving:
// clearForm();

return true;
} catch (err) {
console.log(err);
alert("Save failed (network/server): " + err.message);
return false;
}
}

window.onload = function () {
let ret = configure();
Expand Down
43 changes: 43 additions & 0 deletions submit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
header("Content-Type: text/plain; charset=UTF-8");

$raw = file_get_contents("php://input");
if ($raw === false || trim($raw) === "") {
http_response_code(400);
echo "No data received";
exit;
}

// If it looks like a form-encoded post (e.g. "data=..."), extract the "data" field.
// Otherwise treat the raw body as the TSV.
$data = $raw;
if (strpos($raw, "data=") === 0) {
$post = [];
parse_str($raw, $post);
$data = isset($post["data"]) ? $post["data"] : "";
}

$data = trim($data);
if ($data === "") {
http_response_code(400);
echo "No data received";
exit;
}

// Normalize newlines, then ensure exactly one trailing newline
$data = str_replace("\r\n", "\n", $data);
if (substr($data, -1) !== "\n") {
$data .= "\n";
}

// Append to data.txt (in the SAME directory as submit.php)
$csvFile = __DIR__ . DIRECTORY_SEPARATOR . "data.txt";

if (file_put_contents($csvFile, $data, FILE_APPEND | LOCK_EX) === false) {
http_response_code(500);
echo "Error appending data";
exit;
}

echo "Data appended successfully";
?>
13 changes: 13 additions & 0 deletions teams.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
match,robot,team_number,team_name
1,r1,5492,Robo Jockeys
1,r2,2910,Jack in the Bot
1,r3,2056,OP Robotics
1,b1,1678,Citrus Circuits
1,b2,118,Robonauts
1,b3,111,WildStang
2,r1,254,The Cheesy Poofs
2,r2,4414,HighTide
2,r3,1676,Passaic Pioneers
2,b1,330,Beach Bots
2,b2,71,Team Hammond
2,b3,148,Robowranglers