Skip to content

Commit 255ba9b

Browse files
committed
dynamic schedule ui adding
1 parent 8e321de commit 255ba9b

File tree

1 file changed

+168
-40
lines changed

1 file changed

+168
-40
lines changed

wled00/data/settings_time.htm

Lines changed: 168 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<script>
99
var el=false;
1010
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
11+
var maxTimePresets = 16; // Maximum number of time-controlled presets
12+
var currentPresetCount = 3; // Current number of presets (sunrise + sunset + 1 permanent time preset)
1113
function S() {
1214
getLoc();
1315
loadJS(getURL('/settings/s.js?p=5'), false, ()=>{BTa();}, ()=>{
@@ -27,60 +29,183 @@
2729
function BTa()
2830
{
2931
var ih="<thead><tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr></thead>";
30-
for (i=0;i<8;i++) {
31-
ih+=`<tr><td><input name="W${i}" id="W${i}" type="hidden"><input id="W${i}0" type="checkbox"></td>
32-
<td><input name="H${i}" class="xs" type="number" min="0" max="24"></td>
33-
<td><input name="N${i}" class="xs" type="number" min="0" max="59"></td>
32+
// Generate sunrise preset (0)
33+
ih += generatePresetRow(0, true, "Sunrise");
34+
// Generate sunset preset (1)
35+
ih += generatePresetRow(1, true, "Sunset");
36+
// Generate one permanent time preset (2)
37+
ih += generatePresetRow(2, false, null, false);
38+
// Generate any additional dynamic presets (starting from 3)
39+
for (i=3; i<currentPresetCount; i++) {
40+
ih += generatePresetRow(i, false, null, true);
41+
}
42+
gId("TMT").innerHTML=ih;
43+
}
44+
45+
function generatePresetRow(i, isSunEvent = false, sunType = null, isDynamic = false) {
46+
var ih = "";
47+
var hourInput = isSunEvent ?
48+
`${sunType}<input name="H${i}" value="255" type="hidden">` :
49+
`<input name="H${i}" class="xs" type="number" min="0" max="24">`;
50+
51+
ih += `<tr id="preset-row-${i}"><td><input name="W${i}" id="W${i}" type="hidden"><input id="W${i}0" type="checkbox"></td>
52+
<td>${hourInput}</td>
53+
<td><input name="N${i}" class="xs" type="number" min="${isSunEvent ? '-59' : '0'}" max="59"></td>
3454
<td><input name="T${i}" class="s" type="number" min="0" max="250"></td>
3555
<td><div id="CB${i}" onclick="expand(this,${i})" class="cal">&#128197;</div></td></tr>`;
36-
ih+=`<tr><td colspan=5><div id="WD${i}" style="display:none;background-color:#444;"><hr>Run on weekdays`;
37-
ih+=`<table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`
38-
for (j=1;j<8;j++) ih+=`<td><input id="W${i}${j}" type="checkbox"></td>`;
39-
ih+=`</tr></table>from <select name="M${i}">`;
40-
for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
41-
ih+=`</select><input name="D${i}" class="xs" type="number" min="1" max="31"></input> to <select name="P${i}">`;
42-
for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
43-
ih+=`</select><input name="E${i}" class="xs" type="number" min="1" max="31"></input>
44-
<hr></div></td></tr>`;
56+
57+
ih += `<tr id="preset-detail-${i}"><td colspan=5><div id="WD${i}" style="display:none;background-color:#444;"><hr>`;
58+
59+
if (!isSunEvent) {
60+
ih += "Run on weekdays";
61+
}
62+
63+
ih += `<table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
64+
for (j=1;j<8;j++) ih += `<td><input id="W${i}${j}" type="checkbox"></td>`;
65+
ih += "</tr></table>";
66+
67+
if (!isSunEvent) {
68+
ih += `from <select name="M${i}">`;
69+
for (j=0;j<12;j++) ih += `<option value="${j+1}">${ms[j]}</option>`;
70+
ih += `</select><input name="D${i}" class="xs" type="number" min="1" max="31"></input> to <select name="P${i}">`;
71+
for (j=0;j<12;j++) ih += `<option value="${j+1}">${ms[j]}</option>`;
72+
ih += `</select><input name="E${i}" class="xs" type="number" min="1" max="31"></input>`;
73+
}
74+
75+
ih += "<hr></div></td></tr>";
76+
return ih;
77+
}
78+
79+
function addTimePreset() {
80+
if (currentPresetCount >= maxTimePresets) {
81+
alert(`Maximum of ${maxTimePresets} time presets allowed.`);
82+
return;
83+
}
84+
85+
var table = gId("TMT");
86+
var newRowHTML = generatePresetRow(currentPresetCount, false, null, true);
87+
table.insertAdjacentHTML("beforeend", newRowHTML);
88+
89+
currentPresetCount++;
90+
updateButtonStates();
91+
}
92+
93+
function removePreset(index) {
94+
if (index < 3) {
95+
alert("Cannot remove built-in presets (Sunrise, Sunset, and first time preset).");
96+
return;
97+
}
98+
99+
// Remove the preset rows
100+
var presetRow = gId(`preset-row-${index}`);
101+
var detailRow = gId(`preset-detail-${index}`);
102+
103+
if (presetRow) presetRow.remove();
104+
if (detailRow) detailRow.remove();
105+
106+
// Reindex remaining presets
107+
reindexPresets();
108+
currentPresetCount--;
109+
updateButtonStates();
110+
}
111+
112+
function removeLastPreset() {
113+
if (currentPresetCount <= 3) {
114+
alert("Cannot remove built-in presets. Only dynamic presets (3+) can be removed.");
115+
return;
116+
}
117+
118+
// Find the highest index dynamic preset and remove it
119+
var lastIndex = currentPresetCount - 1;
120+
removePreset(lastIndex);
121+
}
122+
123+
function reindexPresets() {
124+
var table = gId("TMT");
125+
var rows = table.querySelectorAll("tr[id^='preset-row-']");
126+
var newIndex = 3;
127+
128+
rows.forEach((row) => {
129+
var oldIndex = row.id.split('-')[2];
130+
if (parseInt(oldIndex) >= 3) {
131+
updatePresetRowIndex(row, oldIndex, newIndex);
132+
var detailRow = gId(`preset-detail-${oldIndex}`);
133+
if (detailRow) {
134+
updatePresetDetailRowIndex(detailRow, oldIndex, newIndex);
135+
}
136+
newIndex++;
137+
}
138+
});
139+
}
140+
141+
function updatePresetRowIndex(row, oldIndex, newIndex) {
142+
row.id = `preset-row-${newIndex}`;
143+
row.innerHTML = row.innerHTML
144+
.replace(new RegExp(`name="W${oldIndex}"`, 'g'), `name="W${newIndex}"`)
145+
.replace(new RegExp(`id="W${oldIndex}`, 'g'), `id="W${newIndex}`)
146+
.replace(new RegExp(`name="H${oldIndex}"`, 'g'), `name="H${newIndex}"`)
147+
.replace(new RegExp(`name="N${oldIndex}"`, 'g'), `name="N${newIndex}"`)
148+
.replace(new RegExp(`name="T${oldIndex}"`, 'g'), `name="T${newIndex}"`)
149+
.replace(new RegExp(`id="CB${oldIndex}"`, 'g'), `id="CB${newIndex}"`)
150+
.replace(new RegExp(`expand\(this,${oldIndex}\)`, 'g'), `expand(this,${newIndex})`)
151+
.replace(new RegExp(`removePreset\(${oldIndex}\)`, 'g'), `removePreset(${newIndex})`);
152+
}
153+
154+
function updatePresetDetailRowIndex(row, oldIndex, newIndex) {
155+
row.id = `preset-detail-${newIndex}`;
156+
row.innerHTML = row.innerHTML
157+
.replace(new RegExp(`id="WD${oldIndex}"`, 'g'), `id="WD${newIndex}"`)
158+
.replace(new RegExp(`id="W${oldIndex}`, 'g'), `id="W${newIndex}`)
159+
.replace(new RegExp(`name="M${oldIndex}"`, 'g'), `name="M${newIndex}"`)
160+
.replace(new RegExp(`name="D${oldIndex}"`, 'g'), `name="D${newIndex}"`)
161+
.replace(new RegExp(`name="P${oldIndex}"`, 'g'), `name="P${newIndex}"`)
162+
.replace(new RegExp(`name="E${oldIndex}"`, 'g'), `name="E${newIndex}"`);
163+
}
164+
165+
function updateButtonStates() {
166+
var addBtn = gId("addPresetBtn");
167+
var removeBtn = gId("removePresetBtn");
168+
169+
if (addBtn) {
170+
addBtn.disabled = currentPresetCount >= maxTimePresets;
171+
}
172+
173+
if (removeBtn) {
174+
removeBtn.disabled = currentPresetCount <= 3;
45175
}
46-
ih+=`<tr><td><input name="W8" id="W8" type="hidden"><input id="W80" type="checkbox"></td>
47-
<td>Sunrise<input name="H8" value="255" type="hidden"></td>
48-
<td><input name="N8" class="xs" type="number" min="-59" max="59"></td>
49-
<td><input name="T8" class="s" type="number" min="0" max="250"></td>
50-
<td><div id="CB8" onclick="expand(this,8)" class="cal">&#128197;</div></td></tr><tr><td colspan=5>`;
51-
ih+=`<div id="WD8" style="display:none;background-color:#444;"><hr><table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
52-
for (j=1;j<8;j++) ih+=`<td><input id="W8${j}" type="checkbox"></td>`;
53-
ih+="</tr></table><hr></div></td></tr>";
54-
ih+=`<tr><td><input name="W9" id="W9" type="hidden"><input id="W90" type="checkbox"></td>
55-
<td>Sunset<input name="H9" value="255" type="hidden"></td>
56-
<td><input name="N9" class="xs" type="number" min="-59" max="59"></td>
57-
<td><input name="T9" class="s" type="number" min="0" max="250"></td>
58-
<td><div id="CB9" onclick="expand(this,9)" class="cal">&#128197;</div></td></tr><tr><td colspan=5>`;
59-
ih+=`<div id="WD9" style="display:none;background-color:#444;"><hr><table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
60-
for (j=1;j<8;j++) ih+=`<td><input id="W9${j}" type="checkbox"></td>`;
61-
ih+="</tr></table><hr></div></td></tr>";
62-
gId("TMT").innerHTML=ih;
63176
}
64177
function FC()
65178
{
66-
for(i=0;i<10;i++)
179+
for(i=0;i<currentPresetCount;i++)
67180
{
68-
let wd = gId("W"+i).value;
181+
let wd = gId("W"+i);
182+
if (!wd) continue; // Skip if preset doesn't exist
183+
wd = wd.value;
69184
for(j=0;j<8;j++) {
70-
gId("W"+i+j).checked=wd>>j&1;
185+
let checkbox = gId("W"+i+j);
186+
if (checkbox) checkbox.checked=wd>>j&1;
71187
}
72-
if ((wd&254) != 254 || (i<8 && (gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31))) {
73-
expand(gId("CB"+i),i); //expand macros with custom DOW or date range set
188+
if ((wd&254) != 254 || (i<8 && (gN("M"+i) && gN("D"+i) && gN("P"+i) && gN("E"+i) &&
189+
(gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31)))) {
190+
let cbElement = gId("CB"+i);
191+
if (cbElement) expand(cbElement,i); //expand macros with custom DOW or date range set
74192
}
75193
}
194+
updateAddButtonState();
76195
}
77196
function Wd()
78197
{
79-
a = [0,0,0,0,0,0,0,0,0,0];
80-
for (i=0; i<10; i++) {
198+
a = [];
199+
for (i=0; i<currentPresetCount; i++) {
200+
a[i] = 0;
81201
m=1;
82-
for(j=0;j<8;j++) { a[i]+=gId(("W"+i)+j).checked*m; m*=2;}
83-
gId("W"+i).value=a[i];
202+
for (j=0; j<8; j++) {
203+
let checkbox = gId("W"+i+j);
204+
if (checkbox && checkbox.checked) a[i]+=m;
205+
m*=2;
206+
}
207+
let hiddenInput = gId("W"+i);
208+
if (hiddenInput) hiddenInput.value = a[i];
84209
}
85210
if (d.Sf.LTR.value==="S") { d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); }
86211
if (d.Sf.LNR.value==="W") { d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); }
@@ -207,7 +332,10 @@ <h3>Button actions</h3>
207332
<a href="https://kno.wled.ge/features/macros/#analog-button" target="_blank">Analog Button setup</a>
208333
<h3>Time-controlled presets</h3>
209334
<div style="display: inline-block">
210-
<table id="TMT" style="min-width:330px;"></table>
335+
<table id="TMT" style="min-width:380px; margin: 0 auto;"></table>
336+
<br>
337+
<button type="button" id="addPresetBtn" onclick="addTimePreset()">+</button>
338+
<button type="button" id="removePresetBtn" onclick="removeLastPreset()" style="margin-left: 5px;">-</button>
211339
</div>
212340
<hr>
213341
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>

0 commit comments

Comments
 (0)