1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-03-25 01:14:43 +00:00

Added a dynamic score form on the stats page, added stats page form validation on the in js to compliment the validation already in place on the model, and added the wrestler's score in the winner dropdown of the form.

This commit is contained in:
2025-01-19 20:35:33 -05:00
parent c45ec8ab38
commit 288cb6704e
4 changed files with 543 additions and 163 deletions

View File

@@ -295,4 +295,8 @@ class Wrestler < ApplicationRecord
def short_bracket_name
return "#{self.name} (#{self.school.abbreviation})"
end
def name_with_school
return "#{self.name} - #{self.school.name}"
end
end

View File

@@ -41,7 +41,7 @@
<button id="w1-nf2" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'N2')">N2 </button>
<button id="w1-nf3" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'N3')">N3</button>
<button id="w1-nf4" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'N4')">N4</button>
<button id="w1-nf5" type="button" class="btn btn-success btn-sm" onclick="updateStats(w2,'N5')">N5</button>
<button id="w1-nf5" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'N5')">N5</button>
<button id="w1-penalty" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'P1')">P1</button>
<button id="w1-penalty2" type="button" class="btn btn-success btn-sm" onclick="updateStats(w1,'P2')">P2</button></td>
<td><%= @wrestler2_name %> Scoring <br><button id="w2-takedown" type="button" class="btn btn-danger btn-sm" onclick="updateStats(w2,'T3')">T3</button>
@@ -71,7 +71,34 @@
<button id="w2-caution" type="button" class="btn btn-danger btn-sm" onclick="updateStats(w2,'C')">Caution</button></td>
</tr>
<tr>
<td>Match Options <br><button type="button" class="btn btn-primary btn-sm" onclick="updateStats(w2,'|End Period|');updateStats(w1,'|End Period|')">End Period</button></td>
<td>Match Options <br><button type="button" class="btn btn-primary btn-sm" onclick="updateStats(w2,'|End Period|'); updateStats(w1,'|End Period|');">End Period</button></td>
<td></td>
</tr>
<tr>
<td>
<h5><%= @wrestler1_name %> Timer Controls</h5>
Injury Time (90 second max): <span id="w1-injury-time">0 sec</span>
<button type="button" onclick="startTimer(w1, 'injury')" class="btn btn-primary btn-sm">Start</button>
<button type="button" onclick="stopTimer(w1, 'injury')" class="btn btn-primary btn-sm">Stop</button>
<button type="button" onclick="resetTimer(w1, 'injury')" class="btn btn-primary btn-sm">Reset</button>
<br><br>
Blood Time (600 second max): <span id="w1-blood-time">0 sec</span>
<button type="button" onclick="startTimer(w1, 'blood')" class="btn btn-primary btn-sm">Start</button>
<button type="button" onclick="stopTimer(w1, 'blood')" class="btn btn-primary btn-sm">Stop</button>
<button type="button" onclick="resetTimer(w1, 'blood')" class="btn btn-primary btn-sm">Reset</button>
</td>
<td>
<h5><%= @wrestler2_name %> Timer Controls</h5>
Injury Time (90 second max): <span id="w2-injury-time">0 sec</span>
<button type="button" onclick="startTimer(w2, 'injury')" class="btn btn-primary btn-sm">Start</button>
<button type="button" onclick="stopTimer(w2, 'injury')" class="btn btn-primary btn-sm">Stop</button>
<button type="button" onclick="resetTimer(w2, 'injury')" class="btn btn-primary btn-sm">Reset</button>
<br><br>
Blood Time (600 second max): <span id="w2-blood-time">0 sec</span>
<button type="button" onclick="startTimer(w2, 'blood')" class="btn btn-primary btn-sm">Start</button>
<button type="button" onclick="stopTimer(w2, 'blood')" class="btn btn-primary btn-sm">Stop</button>
<button type="button" onclick="resetTimer(w2, 'blood')" class="btn btn-primary btn-sm">Reset</button>
</td>
</tr>
</tbody>
</table>
@@ -92,13 +119,33 @@
<br>
<div class="field">
<%= f.label "Winner" %> Please choose the winner<br>
<%= f.collection_select :winner_id, @wrestlers, :id, :name, include_blank: true %>
<%= f.collection_select :winner_id, @wrestlers, :id, :name_with_school, include_blank: true %>
</div>
<br>
<div class="field">
<%= f.label "Final Score" %> For decision, major, or tech fall put the score here in Number-Number format. If pin, put the accumulated pin time in the format MM:SS. If default, injury default, dq, bye, or forfeit, leave blank. Examples: 7-2, 17-2, 0:30, or 2:34.<br>
<%= f.text_field :score %>
</div>
<% if @match.finished && @match.finished == 1 %>
<div class="field">
<%= f.label "Final Score" %> For decision, major, or tech fall put the score here in Number-Number format. If pin, put the accumulated pin time in the format MM:SS. If default, injury default, dq, bye, or forfeit, leave blank. Examples: 7-2, 17-2, 0:30, or 2:34.<br>
<%= f.text_field :score %>
</div>
<% else %>
<div class="field">
<%= f.label "Final Score" %>
<br>
<span id="score-help-text">
The input will adjust based on the selected win type.
</span>
<br>
<div id="dynamic-score-input"></div>
<p id="pin-time-tip" class="text-muted mt-2" style="display: none;">
<strong>Tip:</strong> Pin time is an accumulation over the match, not how much time was left in the current period.
<br>For example, if all 3 periods are 2 minutes and a pin happened with 1:27 left in the second period,
the pin time would be <strong>2:33</strong> (2 minutes for the first period + 33 seconds elapsed in the second period).
</p>
<div id="validation-alerts" class="text-danger mt-2"></div>
<%= f.hidden_field :score, id: "final-score-field" %>
</div>
<%= render 'matches/matchstats_variable_score_input' %>
<% end %>
<br>
<%= f.hidden_field :finished, :value => 1 %>
@@ -106,173 +153,178 @@
<br>
<div class="actions">
<%= f.submit onclick: "return confirm('Is the name of the winner ' + document.getElementById('match_winner_id').options[document.getElementById('match_winner_id').selectedIndex].text + '?')", :class=>"btn btn-success" %>
</div>
<div class="actions">
<%= f.submit "Update Match", id: "update-match-btn", onclick: "return confirm('Is the name of the winner ' + document.getElementById('match_winner_id').options[document.getElementById('match_winner_id').selectedIndex].text + '?')", class: "btn btn-success" %>
</div>
<% end %>
<%= render 'matches/matchstats_color_change' %>
<script>
// Localstorage
// https://stackoverflow.com/questions/12806198/how-do-i-save-data-on-localstorage-in-ruby-on-rails-3-2-8
// Get variables
var tournament = <%= @match.tournament.id %>;
var bout = <%= @match.bout_number %>;
var match_finsihed = "<%= @match.finished %>";
//Create person object
function Person(stats){
this.stats=stats;
}
// ############### STATS
// Create person object
function Person(stats, name) {
this.name = name;
this.stats = stats;
this.updated_at = null; // Track last updated timestamp
this.timers = {
"injury": { time: 0, startTime: null, interval: null },
"blood": { time: 0, startTime: null, interval: null },
};
}
//Declare variables
var w1=new Person("");
var w2=new Person("");
updatejsvalues();
// Declare variables
var w1 = new Person("", "w1");
var w2 = new Person("", "w2");
updateJsValues();
// Get variables
var tournament=<%= @match.tournament.id %>;
var bout=<%= @match.bout_number %>;
// Generate unique localStorage key
function generateKey(wrestler_name) {
return `${wrestler_name}-${tournament}-${bout}`;
}
// if localstorage tournament id and bout number are the same and the html stat values are blank
// if the html stat values are not blank we want to honor what came from the db
if (localStorage.getItem('wrestler1') && localStorage.tournament == tournament && localStorage.bout == bout && document.getElementById("match_w1_stat").value == "" && document.getElementById("match_w2_stat").value == "") {
w1.stats = localStorage.getItem('wrestler1');
w2.stats = localStorage.getItem('wrestler2');
updatehtmlvalues();
} else {
updateLocalStorage();
}
// Load values from localStorage
function loadFromLocalStorage(wrestler_name) {
const key = generateKey(wrestler_name);
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
}
// Save values to localStorage
function saveToLocalStorage(person) {
const key = generateKey(person.name);
const data = {
stats: person.stats,
updated_at: person.updated_at,
timers: person.timers, // Save all timers
};
localStorage.setItem(key, JSON.stringify(data));
}
function updatehtmlvalues(){
document.getElementById("match_w1_stat").value = w1.stats;
document.getElementById("match_w2_stat").value = w2.stats;
// Update HTML values
function updateHtmlValues() {
document.getElementById("match_w1_stat").value = w1.stats;
document.getElementById("match_w2_stat").value = w2.stats;
}
// Update JS object values from HTML
function updateJsValues() {
w1.stats = document.getElementById("match_w1_stat").value;
w2.stats = document.getElementById("match_w2_stat").value;
}
// Update stats and persist to localStorage
function updateStats(wrestler, text) {
updateJsValues();
wrestler.stats += text + " ";
wrestler.updated_at = new Date().toISOString(); // Update timestamp
updateHtmlValues();
// Save to localStorage
if (wrestler === w1) {
saveToLocalStorage(w1);
} else if (wrestler === w2) {
saveToLocalStorage(w2);
}
function updatejsvalues(){
w1.stats=document.getElementById("match_w1_stat").value;
w2.stats=document.getElementById("match_w2_stat").value;
}
function takedown(wrestler){
updateStats(wrestler,"T3")
}
function updateStats(wrestler,text){
updatejsvalues();
wrestler.stats = wrestler.stats + text + " ";
updatehtmlvalues();
updateLocalStorage();
}
function updateLocalStorage(){
localStorage.setItem("wrestler1",w1.stats);
localStorage.setItem("wrestler2",w2.stats);
localStorage.setItem("bout", bout);
localStorage.setItem("tournament", tournament);
}
//For Changing button colors
function changeW1Color(color){
if (color.value == "red") {
w1Red();
w2Green();
document.getElementById("w2-color").value = "green";
}
if (color.value == "green") {
w1Green();
w2Red();
document.getElementById("w2-color").value = "red";
}
// Initialize data on page load
function initializeTimers(wrestler) {
// Iterate over each timer in the wrestler object
Object.keys(wrestler.timers).forEach((timerKey) => {
const savedData = loadFromLocalStorage(wrestler.name);
if (savedData && savedData.timers && savedData.timers[timerKey]) {
wrestler.timers[timerKey].time = savedData.timers[timerKey].time || 0;
updateTimerDisplay(wrestler, timerKey, wrestler.timers[timerKey].time);
}
});
}
function initialize() {
const localW1 = loadFromLocalStorage("w1");
const localW2 = loadFromLocalStorage("w2");
if (localW1) {
w1.stats = localW1.stats || "";
w1.updated_at = localW1.updated_at || null;
w1.timers = localW1.timers || w1.timers; // Load timer data
// set localStorage values to html
updateHtmlValues();
}
function changeW2Color(color){
if (color.value == "red") {
w2Red();
w1Green();
document.getElementById("w1-color").value = "green";
}
if (color.value == "green") {
w2Green();
w1Red();
document.getElementById("w1-color").value = "red";
}
if (localW2) {
w2.stats = localW2.stats || "";
w2.updated_at = localW2.updated_at || null;
w2.timers = localW2.timers || w2.timers; // Load timer data
// set localStorage values to html
updateHtmlValues();
}
function redColor(id){
document.getElementById(id).className = "btn btn-danger btn-sm";
initializeTimers(w1);
initializeTimers(w2);
updateJsValues()
}
document.addEventListener("DOMContentLoaded", function () {
initialize();
});
// ############### Blood and Injury time timers
// Timer storage and interval references
// Start a timer for a wrestler
function startTimer(wrestler, timerKey) {
const timer = wrestler.timers[timerKey];
if (timer.interval) return; // Prevent multiple intervals
timer.startTime = Date.now(); // Record the start time
timer.interval = setInterval(() => {
const elapsedSeconds = Math.floor((Date.now() - timer.startTime) / 1000);
updateTimerDisplay(wrestler, timerKey, timer.time + elapsedSeconds); // Show total time
}, 1000);
}
// Stop a timer for a wrestler
function stopTimer(wrestler, timerKey) {
const timer = wrestler.timers[timerKey];
if (!timer.interval || !timer.startTime) return; // Timer not running
clearInterval(timer.interval);
const elapsedSeconds = Math.floor((Date.now() - timer.startTime) / 1000); // Calculate elapsed time
timer.time += elapsedSeconds; // Add elapsed time to total
timer.interval = null;
timer.startTime = null;
saveToLocalStorage(wrestler); // Save wrestler data
updateTimerDisplay(wrestler, timerKey, timer.time); // Update final display
updateStatsBox(wrestler, timerKey, elapsedSeconds); // Update wrestler stats
}
// Reset a timer for a wrestler
function resetTimer(wrestler, timerKey) {
const timer = wrestler.timers[timerKey];
stopTimer(wrestler, timerKey); // Stop if running
timer.time = 0; // Reset time
updateTimerDisplay(wrestler, timerKey, 0); // Update display
saveToLocalStorage(wrestler); // Save wrestler data
}
// Update the timer display
function updateTimerDisplay(wrestler, timerKey, totalTime) {
const elementId = `${wrestler.name}-${timerKey}-time`; // Construct element ID
const element = document.getElementById(elementId);
if (element) {
element.innerText = `${Math.floor(totalTime / 60)}m ${totalTime % 60}s`;
}
function greenColor(id){
document.getElementById(id).className = "btn btn-success btn-sm";
}
function w1Red(){
redColor("w1-takedown");
redColor("w1-escape");
redColor("w1-reversal");
redColor("w1-penalty");
redColor("w1-penalty2");
redColor("w1-nf5");
redColor("w1-nf4");
redColor("w1-nf3");
redColor("w1-nf2");
redColor("w1-top");
redColor("w1-bottom");
redColor("w1-neutral");
redColor("w1-defer");
redColor("w1-stalling");
redColor("w1-caution");
}
function w1Green(){
greenColor("w1-takedown");
greenColor("w1-escape");
greenColor("w1-reversal");
greenColor("w1-penalty");
greenColor("w1-penalty2");
greenColor("w1-nf5");
greenColor("w1-nf4");
greenColor("w1-nf3");
greenColor("w1-nf2");
greenColor("w1-top");
greenColor("w1-bottom");
greenColor("w1-neutral");
greenColor("w1-defer");
greenColor("w1-stalling");
greenColor("w1-caution");
}
function w2Red(){
redColor("w2-takedown");
redColor("w2-escape");
redColor("w2-reversal");
redColor("w2-penalty");
redColor("w2-penalty2");
redColor("w2-nf5");
redColor("w2-nf4");
redColor("w2-nf3");
redColor("w2-nf2");
redColor("w2-top");
redColor("w2-bottom");
redColor("w2-neutral");
redColor("w2-defer");
redColor("w2-stalling");
redColor("w2-caution");
}
function w2Green(){
greenColor("w2-takedown");
greenColor("w2-escape");
greenColor("w2-reversal");
greenColor("w2-penalty");
greenColor("w2-penalty2");
greenColor("w2-nf5");
greenColor("w2-nf4");
greenColor("w2-nf3");
greenColor("w2-nf2");
greenColor("w2-top");
greenColor("w2-bottom");
greenColor("w2-neutral");
greenColor("w2-defer");
greenColor("w2-stalling");
greenColor("w2-caution");
}
</script>
}
// Update wrestler stats box with elapsed timer information
function updateStatsBox(wrestler, timerKey, elapsedSeconds) {
const timerType = timerKey.includes("injury") ? "Injury Time" : "Blood Time";
const formattedTime = `${Math.floor(elapsedSeconds / 60)}m ${elapsedSeconds % 60}s`;
updateStats(wrestler, `${timerType}: ${formattedTime}`);
}
</script>

View File

@@ -0,0 +1,108 @@
<script>
// ############### Button color change red/green
function changeW1Color(color){
if (color.value == "red") {
w1Red();
w2Green();
document.getElementById("w2-color").value = "green";
}
if (color.value == "green") {
w1Green();
w2Red();
document.getElementById("w2-color").value = "red";
}
}
function changeW2Color(color){
if (color.value == "red") {
w2Red();
w1Green();
document.getElementById("w1-color").value = "green";
}
if (color.value == "green") {
w2Green();
w1Red();
document.getElementById("w1-color").value = "red";
}
}
function redColor(id){
document.getElementById(id).className = "btn btn-danger btn-sm";
}
function greenColor(id){
document.getElementById(id).className = "btn btn-success btn-sm";
}
function w1Red(){
redColor("w1-takedown");
redColor("w1-escape");
redColor("w1-reversal");
redColor("w1-penalty");
redColor("w1-penalty2");
redColor("w1-nf5");
redColor("w1-nf4");
redColor("w1-nf3");
redColor("w1-nf2");
redColor("w1-top");
redColor("w1-bottom");
redColor("w1-neutral");
redColor("w1-defer");
redColor("w1-stalling");
redColor("w1-caution");
}
function w1Green(){
greenColor("w1-takedown");
greenColor("w1-escape");
greenColor("w1-reversal");
greenColor("w1-penalty");
greenColor("w1-penalty2");
greenColor("w1-nf5");
greenColor("w1-nf4");
greenColor("w1-nf3");
greenColor("w1-nf2");
greenColor("w1-top");
greenColor("w1-bottom");
greenColor("w1-neutral");
greenColor("w1-defer");
greenColor("w1-stalling");
greenColor("w1-caution");
}
function w2Red(){
redColor("w2-takedown");
redColor("w2-escape");
redColor("w2-reversal");
redColor("w2-penalty");
redColor("w2-penalty2");
redColor("w2-nf5");
redColor("w2-nf4");
redColor("w2-nf3");
redColor("w2-nf2");
redColor("w2-top");
redColor("w2-bottom");
redColor("w2-neutral");
redColor("w2-defer");
redColor("w2-stalling");
redColor("w2-caution");
}
function w2Green(){
greenColor("w2-takedown");
greenColor("w2-escape");
greenColor("w2-reversal");
greenColor("w2-penalty");
greenColor("w2-penalty2");
greenColor("w2-nf5");
greenColor("w2-nf4");
greenColor("w2-nf3");
greenColor("w2-nf2");
greenColor("w2-top");
greenColor("w2-bottom");
greenColor("w2-neutral");
greenColor("w2-defer");
greenColor("w2-stalling");
greenColor("w2-caution");
}
</script>

View File

@@ -0,0 +1,216 @@
<script>
// ############### Score field changer and form validation
document.addEventListener("DOMContentLoaded", () => {
const winTypeSelect = document.getElementById("match_win_type");
const winnerSelect = document.getElementById("match_winner_id");
const submitButton = document.getElementById("update-match-btn");
const dynamicScoreInput = document.getElementById("dynamic-score-input");
const finalScoreField = document.getElementById("final-score-field");
const validationAlerts = document.getElementById("validation-alerts");
const pinTimeTip = document.getElementById("pin-time-tip");
// Variables to persist scores across win type changes
let storedScores = {
winnerScore: "0",
loserScore: "0",
};
function updateScoreInput() {
const winType = winTypeSelect.value;
if (winType === "Pin") {
if (
dynamicScoreInput.querySelector("#minutes") &&
dynamicScoreInput.querySelector("#seconds")
) {
validateForm(); // Trigger validation
return;
}
// Clear existing form and create Pin inputs
dynamicScoreInput.innerHTML = "";
pinTimeTip.style.display = "block";
const minuteInput = createTextInput("minutes", "Minutes (MM)", "Pin Time Minutes");
const secondInput = createTextInput("seconds", "Seconds (SS)", "Pin Time Seconds");
dynamicScoreInput.appendChild(minuteInput);
dynamicScoreInput.appendChild(secondInput);
const updateFinalScore = () => {
const minutes = minuteInput.value.padStart(2, "0");
const seconds = secondInput.value.padStart(2, "0");
finalScoreField.value = `${minutes}:${seconds}`;
validateForm();
};
[minuteInput, secondInput].forEach((input) => {
input.addEventListener("input", updateFinalScore);
});
updateFinalScore(); // Set initial value
validateForm(); // Trigger validation
return;
}
if (
winType === "Decision" ||
winType === "Major" ||
winType === "Tech Fall"
) {
if (
dynamicScoreInput.querySelector("#winner-score") &&
dynamicScoreInput.querySelector("#loser-score")
) {
validateForm(); // Trigger validation
return;
}
// Clear existing form and create Score inputs
dynamicScoreInput.innerHTML = "";
pinTimeTip.style.display = "none";
const winnerScoreInput = createTextInput(
"winner-score",
"Winner's Score",
"Enter the winner's score"
);
const loserScoreInput = createTextInput(
"loser-score",
"Loser's Score",
"Enter the loser's score"
);
dynamicScoreInput.appendChild(winnerScoreInput);
dynamicScoreInput.appendChild(loserScoreInput);
// Restore stored values
winnerScoreInput.value = storedScores.winnerScore;
loserScoreInput.value = storedScores.loserScore;
const updateFinalScore = () => {
const winnerScore = winnerScoreInput.value || "0";
const loserScore = loserScoreInput.value || "0";
finalScoreField.value = `${winnerScore}-${loserScore}`;
validateForm();
};
[winnerScoreInput, loserScoreInput].forEach((input) => {
input.addEventListener("input", (event) => {
storedScores[event.target.id === "winner-score" ? "winnerScore" : "loserScore"] =
event.target.value || "0";
updateFinalScore();
});
});
updateFinalScore(); // Set initial value
validateForm(); // Trigger validation
return;
}
// For other types, clear everything
dynamicScoreInput.innerHTML = "";
pinTimeTip.style.display = "none";
finalScoreField.value = ""; // Clear the final score for other win types
validateForm(); // Trigger validation
}
function validateForm() {
const winType = winTypeSelect.value;
const winner = winnerSelect.value;
let isValid = true;
let alertMessage = "";
let winTypeShouldBe = "Decision";
if (winType === "Decision" || winType === "Major" || winType === "Tech Fall") {
const winnerScoreInput = document.getElementById("winner-score");
const loserScoreInput = document.getElementById("loser-score");
if (!winnerScoreInput || !loserScoreInput) return;
const winnerScore = parseInt(winnerScoreInput.value || "0", 10);
const loserScore = parseInt(loserScoreInput.value || "0", 10);
const scoreDifference = winnerScore - loserScore;
if (winnerScore <= loserScore) {
isValid = false;
alertMessage += "Winner's score must be higher than loser's score.<br>";
}
if (scoreDifference < 8) {
winTypeShouldBe = "Decision";
} else if (scoreDifference >= 8 && scoreDifference < 15) {
winTypeShouldBe = "Major";
} else if (scoreDifference >= 15) {
winTypeShouldBe = "Tech Fall";
}
if (winTypeShouldBe !== winType) {
isValid = false;
alertMessage += `
Win type should be <strong>${winTypeShouldBe}</strong>.
Decisions are wins with a score difference less than 8.
Majors are wins with a score difference between 8 and 14.
Tech Falls are wins with a score difference of 15 or more.<br>
`;
}
}
if (!winner) {
isValid = false;
alertMessage += "Please select a winner.<br>";
}
if (!isValid) {
validationAlerts.innerHTML = alertMessage;
validationAlerts.style.display = "block";
} else {
validationAlerts.innerHTML = ""; // Clear alerts
validationAlerts.style.display = "none";
}
submitButton.disabled = !isValid;
}
document.querySelector("form").addEventListener("submit", (event) => {
const winType = winTypeSelect.value;
if (winType === "Pin") {
const minuteInput = document.getElementById("minutes");
const secondInput = document.getElementById("seconds");
if (minuteInput && secondInput) {
const minutes = minuteInput.value.padStart(2, "0");
const seconds = secondInput.value.padStart(2, "0");
finalScoreField.value = `${minutes}:${seconds}`;
}
}
});
winTypeSelect.addEventListener("change", updateScoreInput);
winnerSelect.addEventListener("change", validateForm);
updateScoreInput();
validateForm();
});
// Helper function to create text inputs
function createTextInput(id, placeholder, label) {
const container = document.createElement("div");
container.classList.add("form-group");
const inputLabel = document.createElement("label");
inputLabel.innerText = label;
const input = document.createElement("input");
input.type = "text";
input.id = id;
input.placeholder = placeholder;
input.classList.add("form-control", "form-control-sm");
container.appendChild(inputLabel);
container.appendChild(input);
return container;
}
</script>