528 lines
18 KiB
HTML
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>
|
|
|
|
<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>
|