528 lines
18 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/nav.css" rel="stylesheet">
<script src="event-box.js"></script>
<script src="hue-select.js"></script>
<style>
h1{
text-align: center;
margin: 0;
margin-bottom: 0;
font-size: larger;
}
body {
font-family: Arial, sans-serif;
padding: 0;
justify-content: center;
align-items: center;
background-color: #f0f0f0;
width: 100%;
max-width: 700px;
min-width: 350px;
margin: 0 auto;
}
.outer-container {
justify-content: center;
align-items: center;
padding: 4 20px 20 20px
}
.container {
border: 1px solid #ccc;
padding: 5px 20px 5px 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
width:90%;
}
.center-text {
text-align: center;
font-size: larger;
font-weight: bold;
margin-bottom: 10;
}
.row {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 10px;
}
.row > * {
flex: 0 0 calc(50% - 20px);
margin-bottom: 15px;
}
.row:last-child {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
input[type="range"] {
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
}
select{
width: 50%;
}
button {
background-color: #007bff;
color: #fff;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
#set-countdown-button {
margin-left: 30px; /* Adjust top margin if necessary */
}
</style>
</head>
<body>
<div id="navbar"></div>
<div class="outer-container">
<h1 name="h1element">Lights Configuration</h1>
<div class="container">
<legend class="center-text" id="center-text">Countdown ( Constant Light )</legend>
<div class="row">
<div>
<label id="constLightMin-label" for="constlightMin">Light Min:</label>
<input type="range" name="constLightMin" id="constlightMin" min="0" max="99" value="25" step="1" onchange="updateLabel('Light Min: ', this)">
</div>
<div>
<label id="constLightMax-label" for="constlightMax">Light Max:</label>
<input type="range" name="constLightMax" id="constlightMax" min="1" max="100" value="90" step="1" onchange="updateLabel('Light Max: ', this)">
</div>
</div>
<div class="row">
<div>
<label for="Holdtime">Hold time(ms):</label><br>
<input type="number" name="holdTime" id="holdtime" min="0" max="5000" value="500">
</div>
<div>
<label for="Ramptime">Ramp dn(ms):</label><br>
<input type="number" name="rampTime" id="Ramptime" min="0" max="5000" value="500">
</div>
</div>
<div class="row">
<br>
</div>
<div class="row">
<div>
<label>Active Profile:</label>
<select name= "selActiveAnimProfiles" id="selActivedAnimProfiles" style="width:150px">
<option>(1)</option>
<option>(2)</option>
<option>(3)</option>
<option>(4)</option>
<option>(5)</option>
<option>(6)</option>
<option>(7)</option>
<option>(8)</option>
</select>
</div>
<div>
<button id="testCommon" onclick="SaveProfileCommonToServer(true)">Try</button>
&nbsp;&nbsp;&nbsp;&nbsp;
<button id="saveCommon" onclick="SaveProfileCommonToServer(false)">Save</button>
</div>
</div>
</div>
</div>
<div class="outer-container">
<div class="container">
<legend class="center-text" id="center-text">Saved Animation Profiles</legend>
<div class="row">
<div>
<label for="selSavedAnimProfiles">Profiles:</label>
<select name= "selSavedAnimProfiles" id="selSaveddAnimProfiles" style="width:150px" onchange="OnSavedAnimProfilesChanged(this)">
<option>(1)</option>
<option>(2)</option>
<option>(3)</option>
<option>(4)</option>
<option>(5)</option>
<option>(6)</option>
<option>(7)</option>
<option>(8)</option>
</select>
</div>
<div>
<label for="profileName">Rename:</label>
<input type="text" name="inputProfileName" id="profileName" style="width:140px">
<button id="saveProfile" onclick="SaveProfileToServer()">Save</button>
</div>
</div>
</div>
</div>
<div id="events-container"></div>
<script>
fetch('/www/navbar.html')
.then(response => response.text())
.then(data => {
document.getElementById('navbar').innerHTML = data;
});
window.onload = function() { getProfilesAndEvents(); };
// Initialize Names
const EVENTCOUNT = 12;
const PROFILECOUNT = 8;
var profileCommonJson;
var profileJson = [PROFILECOUNT];
var eventsJson;
var animListJson;
const inputProfileName = document.getElementsByName('inputProfileName')[0];
const selSavedAnimProfiles = document.getElementsByName('selSavedAnimProfiles')[0];
const selActiveAnimProfiles = document.getElementsByName('selActiveAnimProfiles')[0];
const constLightMin = document.getElementsByName('constLightMin')[0];
const constLightMax = document.getElementsByName('constLightMax')[0];
const holdTime = document.getElementsByName('holdTime')[0];
const rampTime = document.getElementsByName('rampTime')[0];
var lastAnimProfileIndex = 0;
var h1element = document.getElementsByName("h1element")[0];
var eventBox = [EVENTCOUNT];
function createEventForms(count){
const eventContainer = document.getElementById('events-container');
for(let i = 0; i < count; i++ ){
const div = document.createElement('div');
eventBox[i] = document.createElement('event-box');
eventBox[i].id = `event${i}`;
eventBox[i].setHidden(true);
eventBox[i].setIndex(i);
eventBox[i].addEventListener('tryClick', handleEventTryClick);
div.appendChild(eventBox[i]);
eventContainer.appendChild(div);
}
}
// Get profiles
// fetch anim-profile-common.json and anim-profile(1-8), events and anim-list
function getProfilesAndEvents() {
try {
fetch_file('cfg/anim-profile-common.json').then(profilesResult => {
profileCommonJson = profilesResult.data;
let profilePromises = [];
for (let i = 1; i <= PROFILECOUNT; i++) {
profilePromises.push(fetch_file(`cfg/anim-profile${i}.json`));
}
Promise.all(profilePromises).then(results => {
profileJson = results.map(result => result.data);
fetch_file('cfg/app-events.json').then(eventsResult => {
eventsJson = eventsResult.data.apps[eventsResult.data.index];
fetch_file('cfg/anim-list.json').then(animListResult => {
animListJson = animListResult.data;
// Title for page
h1element.textContent = eventsJson.name;
// Event Boxes
createEventForms(EVENTCOUNT);
NameAndHideEvents(animListJson);
// Rest
FillProfilesList();
selSavedAnimProfiles.selectedIndex = profileCommonJson['profile-index'];
lastAnimProfileIndex = selSavedAnimProfiles.selectedIndex;
setProfile(selSavedAnimProfiles.selectedIndex);
selActiveAnimProfiles.selectedIndex = profileCommonJson['profile-index'];
});
});
});
}).catch(error => {
console.error(error);
});
} catch (error) {
console.error(error);
}
}
// update the form with animation data when profile list item selected
function setProfile(index){
var changeEvent = new Event("change");
// update common
inputProfileName.value = "";
constLightMin.value = profileCommonJson.countdown.min;
constLightMin.dispatchEvent(changeEvent);
constLightMax.value = profileCommonJson.countdown.max;
constLightMax.dispatchEvent(changeEvent);
holdTime.value = profileCommonJson.countdown.hold;
rampTime.value = profileCommonJson.countdown.ramp;
// Update Events
for (let i = 0; i < EVENTCOUNT; i++) {
if(!eventBox[i].getHidden()){
let thisEvent = profileJson[index].events[i];
eventBox[i].setAnimationIndex(thisEvent.anim);
eventBox[i].setHueValue(thisEvent.hue);
eventBox[i].setSpeedValue(thisEvent.speed);
eventBox[i].setHueRangeValue(thisEvent["hue-range"]);
eventBox[i].setParam1Value(thisEvent.param1);
eventBox[i].setParam2Value(thisEvent.param2);
eventBox[i].setCheck1Value(thisEvent.check1);
eventBox[i].setCheck2Value(thisEvent.check2);
eventBox[i].setCheck3Value(thisEvent.check3);
eventBox[i].setCheck4Value(thisEvent.check4);
}
}
}
// When new profile is selected update
function OnSavedAnimProfilesChanged( event ){
console.log('Anim Profile Selected index:', event.selectedIndex);
console.log('Anim Profile Updated index:', lastAnimProfileIndex);
updateSingleProfileJson(lastAnimProfileIndex); // save current setting in ram but not in server yet
setProfile(event.selectedIndex);
lastAnimProfileIndex = event.selectedIndex;
}
//Update the anim-profilesX.json obj with updated values
function updateSingleProfileJson(index){
if(inputProfileName.value != ""){
profileJson[index].name = inputProfileName.value;
selSavedAnimProfiles.options[index].text = '(' + (index + 1) + ') ' + inputProfileName.value;
selSavedAnimProfiles.options[index].value = inputProfileName.value;
}
// Update Events
for (let i = 0; i < EVENTCOUNT; i++) {
profileJson[index].events[i].anim = eventBox[i].getAnimationIndex();
profileJson[index].events[i].hue = eventBox[i].getHueValue();
profileJson[index].events[i].speed = eventBox[i].getSpeedValue();
profileJson[index].events[i]["hue-range"] = eventBox[i].getHueRangeValue();
profileJson[index].events[i].param1 = eventBox[i].getParam1Value();
profileJson[index].events[i].param2 = eventBox[i].getParam2Value();
profileJson[index].events[i].check1 = eventBox[i].getCheck1Value();
profileJson[index].events[i].check2 = eventBox[i].getCheck2Value();
profileJson[index].events[i].check3 = eventBox[i].getCheck3Value();
profileJson[index].events[i].check4 = eventBox[i].getCheck4Value();
}
}
// save profileX.Json
function SaveProfileToServer(){
updateSingleProfileJson(selSavedAnimProfiles.selectedIndex);
const params = new URLSearchParams();
let i = selSavedAnimProfiles.selectedIndex + 1;
params.append('type', `anim-profile${i}`);
const url = '/post?' + params.toString();
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/plain' } ,
body: JSON.stringify(profileJson[selSavedAnimProfiles.selectedIndex]) // convert to string
})
.then(response => {
if (response.ok) { console.log('Request successful');}
else { throw new Error('Request failed');}
})
.catch(error => { console.error(error);});
}
// save profileCommonJson
function SaveProfileCommonToServer(TestOnly){
profileCommonJson.countdown.min = constLightMin.value;
profileCommonJson.countdown.max = constLightMax.value;
profileCommonJson.countdown.hold = holdTime.value;
profileCommonJson.countdown.ramp = rampTime.value;
profileCommonJson["profile-index"] = selActiveAnimProfiles.selectedIndex; // Set at active profile
const params = new URLSearchParams();
params.append('type', TestOnly ? 'set-countdown' : 'anim-profile-common');
const url = '/post?' + params.toString();
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/json' } ,
body: JSON.stringify(profileCommonJson) // convert to string
})
.then(response => {
if (response.ok) { console.log('Request successful');}
else { throw new Error('Request failed');}
})
.catch(error => { console.error(error);});
}
//
function fetch_file(filename){
return fetch(filename)
.then(response => {
if (response.ok) { return response.json(); }
else { throw new Error('fetching ' + fileName + ' failed'); }
})
.then(data => { return{data:data}; })
}
//
function fetch_json_file(fileName){
const params = new URLSearchParams();
params.append('type', fileName);
const url = '/get?' + params.toString();
return fetch(url, {
method: 'GET'
})
.then(response => {
if (response.ok) { return response.json(); }
else { throw new Error('fetching ' + fileName + ' failed'); }
})
.then(data => { return{data:data}; })
}
// Rename legends and or hide unused events property boxes
function NameAndHideEvents(props){
for(let i = 0; i < EVENTCOUNT; i++){
if(eventsJson.events[i] === ''){
break;
}
eventBox[i].setTitle(eventsJson.events[i]);
eventBox[i].setHidden(false);
}
// load captions for white fills box
eventBox[0].setAnimationCaptions(props.whitefills);
// load captions for the rest of the eventBox
for(let i = 1; i < EVENTCOUNT; i++){
eventBox[i].setAnimationCaptions(props.animations);
}
}
// Fill Profiles List
function FillProfilesList(){
for(let i = 0; i < PROFILECOUNT; i++){
selSavedAnimProfiles.options[i].text = '(' + (i + 1) + ') ' + profileJson[i].name;
selSavedAnimProfiles.options[i].value = profileJson[i].name;
selActiveAnimProfiles.options[i].text = selSavedAnimProfiles.options[i].text;
selActiveAnimProfiles.options[i].value = selSavedAnimProfiles.options[i].value;
}
}
// Fill White Animation drop down lists
function FillWhitefilList(whiteJson){
for(let x = 0; x < whiteJson.length; x++){
eventBox[0].addOptionToList(x, whiteJson[x])
}
}
// Fill Animations drop down lists
function FillAnimationsList(animJson){
for(let x = 0; x < animJson.length; x++){
if(animJson[x].name == ""){break;}// stop if blank
for(let i = 1; i < EVENTCOUNT; i++){
eventBox[i].addOptionToList(i, animJson[x].name);
}
}
}
// for const light props
function updateLabel(labelText, slider) {
let label = document.getElementById(slider.name + "-label");
label.innerHTML = labelText + slider.value;
}
// send anim event to test out
function postPlayAnim(i){
let tempAnimProps = {};
tempAnimProps.event = eventIndex;
tempAnimProps.anim = eventBox[i].getAnimationIndex();
tempAnimProps.hue = eventBox[i].getHueValue();
tempAnimProps.speed = eventBox[i].getSpeedValue();
tempAnimProps["hue-range"] = eventBox[i].getHueRangeValue();
tempAnimProps.param1 = eventBox[i].getParam1Value();
tempAnimProps.param2 = eventBox[i].getParam2Value();
tempAnimProps.check1 = eventBox[i].getCheck1Value();
tempAnimProps.check2 = eventBox[i].getCheck2Value();
tempAnimProps.check3 = eventBox[i].getCheck3Value();
tempAnimProps.check4 = eventBox[i].getCheck4Value();
const params = new URLSearchParams();
params.append('type', 'play-anim');
const url = '/post?' + params.toString();
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/plain'} ,
body: JSON.stringify(tempAnimProps)
})
.then(response => {
if (!response.ok) { throw new Error('Request failed'); }
})
.catch(error => { console.error(error); });
}
// send anim event to test out
function postTestCountdown(){
let tempCountdown = {};
tempCountdown.min = constLightMin.value;
tempCountdown.max = constLightMax.value;
tempCountdown.hold = holdTime.value;
tempCountdown.ramp = rampTime.value;
tempCountdown.active_profile = selSavedAnimProfiles.selectedIndex;
const params = new URLSearchParams();
params.append('type', 'set-countdown');
const url = '/post?' + params.toString();
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/plain'} ,
body: JSON.stringify(tempCountdown)
})
.then(response => {
if (!response.ok) { throw new Error('Request failed'); }
})
.catch(error => { console.error(error); });
}
// Post Play Anim
function handleEventTryClick(event) {
let tempAnimProps = {};
tempAnimProps.index = event.detail.eventIndex;
tempAnimProps.anim = event.detail.animIndex;
tempAnimProps.hue = event.detail.hue;
tempAnimProps.speed = event.detail.speed;
tempAnimProps["hue-range"] = event.detail.colorRange;
tempAnimProps.param1 = event.detail.param1;
tempAnimProps.param2 = event.detail.param2;
tempAnimProps.check1= event.detail.check1;
tempAnimProps.check2 = event.detail.check2;
tempAnimProps.check3 = event.detail.check3;
tempAnimProps.check4 = event.detail.check4;
//console.log(tempAnimProps);
const params = new URLSearchParams();
params.append('type', 'play-anim');
const url = '/post?' + params.toString();
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/plain'} ,
body: JSON.stringify(tempAnimProps)
})
.then(response => {
if (!response.ok) { throw new Error('Request failed'); }
})
.catch(error => { console.error(error); });
};
</script>
</body>
</html>