3 var daynames = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
5 function toggleMenu(e) {
6 active = (document.getElementById('menuLink').className.indexOf('active') !== -1)
7 if (active || e.target.id == 'menuLink' || e.target.id == 'menuBtn') {
8 elements = [ document.getElementById('layout'), document.getElementById('menu'), document.getElementById('menuLink') ]
9 for (const element of elements) {
11 element.classList.add('active')
13 element.classList.remove('active')
16 if (e.target.id == 'menuLink' || e.target.id == 'menuBtn') {
23 document.getElementById('layout').addEventListener('click', toggleMenu)
27 return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
30 function getAnchor() {
31 return window.location.hash;
34 function DrawHeader(project) {
35 var menu_header = document.getElementById('_ui_menu_header')
36 menu_header.innerHTML = project.name
37 document.title = project.name + '/' + project.version
40 function ParseJsonQ(url, callback) {
41 var req = new XMLHttpRequest();
43 req.onreadystatechange = function () {
44 if (this.readyState != 4) return;
45 if (this.status != 200 && this.status != 500 && this.status != 404) {
46 setTimeout(ParseJsonQ(url, callback),30000);
49 var json = JSON.parse(this.responseText)
53 req.open("GET", url, true);
58 function UpdateElement(id, value) {
59 var element = document.getElementById("_ui_element_"+id)
61 var ui_class = element.dataset.ui_class;
64 element.innerText = value
74 element.checked = value
78 var subname = '_ui_elpart_'+i+'_'+id
79 var subelement = document.getElementById(subname)
81 subelement.className = "weekday-selected"
83 subelement.className = "weekday"
90 function UpdateValues(json) {
91 for (var key in json) {
92 var obj = document.getElementById("_ui_element_"+key)
94 UpdateElement(key, json[key])
96 parameters[key] = json[key]
98 var notification = document.getElementById('_ui_notification');
99 if (parameters['_changed']) {
100 notification.innerHTML = '<input style="margin:1em .5em 0;" type="button" id="save" value="Сохранить внесенные изменения" class="pure-button pure-button-primary" onclick="sendAction(\'save\')">'
101 notification.removeAttribute('hidden')
103 notification.innerHTML = ''
104 notification.hidden = true
108 function sendUpdate(id) {
109 var input = document.getElementById('_ui_element_'+id)
110 var ui_class = input.dataset.ui_class;
116 if (input.checkValidity() && input.value != parameters[id]) {
117 ParseJsonQ('/config/set?name=' + id + '&value=' + encodeURIComponent(input.value), function(json) {
123 ParseJsonQ('/config/set?name=' + id + '&value=' + encodeURIComponent(input.selectedOptions[0].value), function(json) {
128 ParseJsonQ('/config/set?name=' + id + '&value=' + (input.checked?'true':'false'), function(json) {
133 ParseJsonQ('/config/set?name=' + id + '&value=' + input.dataset.value, function(json) {
140 function sendAction(name) {
141 ParseJsonQ('/action?name=' + name, function(json) {
142 if (json.result == 'FAILED') {
153 function ShowPwd(id) {
154 var x = document.getElementById('_ui_element_' + id)
155 if (x.type === "password") {
162 function OpenSelect(id) {
163 var selector = document.getElementById('_ui_elemmodal_'+id);
164 selector.removeAttribute("hidden")
167 function CloseSelect(id) {
168 var selector = document.getElementById('_ui_elemmodal_'+id);
169 selector.hidden = true
172 function SelectWiFi(id, ssid) {
174 var x = document.getElementById('_ui_element_' + id)
175 UpdateElement(x,ssid);
179 function getWiFi(id) {
180 var list = document.getElementById('_ui_elemselect_'+id)
182 var req = new XMLHttpRequest();
184 req.onreadystatechange = function () {
185 if (this.readyState != 4) return;
186 if (this.status != 200 && this.status != 500 && this.status != 404) {
187 setTimeout(getWiFi(id),30000);
190 var json = JSON.parse(this.responseText)
191 var table = '<table cellpadding="5" border="0" align="center"><thead class="table-header"><tr><td style="padding: 1rem">SSID</td><td style="padding: 1rem">BSSID</td><td style="padding: 1rem">RSSI</td><td style="padding: 1rem">Канал</td><td style="padding: 1rem">Защита</td></tr></thead></tbody style="border-bottom: lightgrey 1px solid">'
193 setTimeout(getWiFi(id),5000);
196 var encryption = json[idx].secure == 2? "TKIP" : json[idx].secure == 5? "WEP" : json[idx].secure == 4? "CCMP" : json[idx].secure == 7? "нет" : json[idx].secure == 8? "Автоматически" : "Не определено";
197 table += '<tr onclick="SelectWiFi(\''+id+'\',\''+json[idx].ssid+'\')"><td style="padding: 1rem">'+json[idx].ssid+'</td><td style="padding: 1rem">'+json[idx].bssid+'</td><td style="padding: 1rem">'+json[idx].rssi+'</td><td style="padding: 1rem">'+json[idx].channel+'</td><td style="padding: 1rem">'+encryption+'</td></tr>'
200 table += '</tbody></table>'
201 list.innerHTML = table;
204 req.open("GET", "/wifi/scan", true);
209 function ClickDay(id, day) {
210 value = parameters[id].split('')
211 day_value = value[day]
212 day_value = (day_value=='0')?'1':'0'
213 value[day] = day_value
214 element = document.getElementById('_ui_element_' + id)
215 value = value.join('')
216 element.dataset.value = value;
220 function ElementHTML(element) {
222 if (parameters[element.id] || !isNaN(parameters[element.id])) {
223 value = parameters[element.id]
224 } else if (element.value) {
225 value = element.value
229 switch (element.type) {
231 return '<div class="pure-u-1 pure-u-md-1-3"><hr></div>'
233 return '<div class="pure-u-1 pure-u-md-1-3"><div align="center"><input style="margin:1em .5em 0;" type="button" id="'
234 + element.id + '" value="' + encode(element.label) + '" class="pure-button pure-button-primary" onclick="sendAction(\'' + element.id + '\')" /></div></div>'
236 return '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
237 + '<input data-ui_class="password" type="password" id="_ui_element_' + element.id + '" value="' + encode(value)
238 + '" class="pure-u-1" style="display:inline-block" maxlength="99" oninput="sendUpdate(\'' + element.id + '\')" />'
239 + '<div class="hint" onclick="ShowPwd(\'' + element.id + '\')"></div></div>'
242 if (element.pattern) {
243 pattern = ' pattern="' + encode(element.pattern) + '"'
245 return '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
246 + '<input data-ui_class="input" type="text" id="_ui_element_' + element.id + '" value="' + encode(value) +'"'+ pattern
247 + ' class="pure-u-1" maxlength="99" oninput="sendUpdate(\'' + element.id + '\')" /></div>'
250 if (element.pattern) {
251 pattern = ' pattern="' + encode(element.pattern) + '"'
253 return '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
254 + '<input data-ui_class="input" type="text" id="_ui_element_' + element.id + '" value="' + encode(value) +'"'+ pattern
255 + ' class="pure-u-1" style="display:inline-block" maxlength="99" oninput="sendUpdate(\'' + element.id + '\')" />'
256 + '<div class="hint" onclick="OpenSelect(\'' + element.id+ '\'); getWiFi(\'' + element.id + '\')"></div>'
257 + '<div class="modal" id="_ui_elemmodal_' + element.id + '" hidden>'
258 + '<div class="modal-content">'
259 + '<div id="_ui_elemselect_' + element.id + '"></div>'
260 + '<div class="pure-u-1 pure-u-md-1-3"><div align="center"><input style="margin:1em .5em 0;" type="button" id="_ui_button_'
261 + element.id + '" value="Закрыть" class="pure-button pure-button-primary" onclick="CloseSelect(\'' + element.id + '\')"></div>'
262 + '</div></div></div>'
264 return '<div class="pure-u-1 pure-u-md-1-3"><label class="switch socket" for="_ui_element_' + element.id + '">'
265 + '<input class="switch" data-ui_class="checkbox" type="checkbox" id="_ui_element_' + element.id + '"' + (parameters[element.id]?' checked':'') + ' onchange="sendUpdate(\'' + element.id + '\')" />'
266 + '<span class="switch slider">'+ encode(element.label) + '</span>'
269 var options = '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
270 + '<select class="pure-u-24-24" data-ui_class="select" id="_ui_element_' + element.id + '" onchange="sendUpdate(\'' + element.id + '\')">'
271 for (const option of element.options) {
272 var list_option = '<option value="' + encode(option.value) + '" ';
273 if (option.value == parameters[element.id]) {
274 list_option += 'selected '
276 list_option += '>' + encode(option.text) + '</option>'
277 options += list_option
279 options += '</select></div>'
282 days = '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
283 + '<table data-ui_class="week" data-value="' + value + '" id="_ui_element_' + element.id + '" cellpadding="5" border="0" class="week"><tbody><tr>'
284 for (i=0; i<7; i++) {
285 a_enabled = (value[i] == "1")
286 days = days + '<td><div class="weekday' + (a_enabled?"-selected":"") + '" id="_ui_elpart_'+i+'_'+element.id+'" onclick="ClickDay(\'' + element.id + '\', ' + i + ')">'+ daynames[i] + '</div></td>'
288 days += '</tr></tbody></table></div>'
291 return '<div class="pure-u-1 pure-u-md-1-3"><h2 id="_ui_element_'+ element.id +'" ' + (element.color?'style="color:'+ element.color+'" ':'')+ '>' + encode(value) + '</h2></div>'
293 return '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
294 + '<input data-ui_class="number" type="number" '+ (!isNaN(element.min)?'min="'+element.min+'" ':'') + (!isNaN(element.max)?'max="'+element.max+'" ':'') + (!isNaN(element.step)?'step="'+element.step+'" ':'')
295 + 'id="_ui_element_' + element.id + '" value="' + encode(value) +'"'+ pattern
296 + ' class="pure-u-1" maxlength="99" oninput="sendUpdate(\'' + element.id + '\')" /></div>'
298 return '<div class="pure-u-1 pure-u-md-1-3"><label for="_ui_element_' + element.id + '">' + encode(element.label) + '</label>'
299 + '<input data-ui_class="range" type="range" '+ (!isNaN(element.min)?'min="'+element.min+'" ':'') + (!isNaN(element.max)?'max="'+element.max+'" ':'') + (!isNaN(element.step)?'step="'+element.step+'" ':'')
300 + 'id="_ui_element_' + element.id + '" value="' + encode(value) +'"'+ pattern
301 + ' class="pure-u-1" maxlength="99" oninput="sendUpdate(\'' + element.id + '\')" /></div>'
304 return '<div class="pure-u-1 pure-u-md-1-3"><table cellpadding="5" border="0" align="center"><tbody><tr><td style="padding-right: 10px; width: 50%;" align="right"><pre>'
305 + encode(element.label)+ '</pre></td><td style="padding-left: 10px;" id="cT"><pre id="_ui_element_'
306 + element.id + '" data-ui_class="table" ' + (element.color?'style="color:'+ element.color+'" ':'')+ '>' + encode(value) + '</pre></td></tr></tbody></table></div>'
310 function DrawPage(id) {
312 for (const page of pages) {
313 var menu_link = document.getElementById('_ui_pglink_' + page.id)
315 menu_link.classList.remove("pure-menu-selected")
317 menu_link.classList.add("pure-menu-selected")
322 var page_header = document.getElementById("_ui_page_header")
323 page_header.innerHTML = pages[idx].title
324 var page_content = document.getElementById("_ui_page_content");
326 for (const element of pages[idx].elements) {
327 content = content + ElementHTML(element) + '\n'
329 page_content.innerHTML = content
330 window.location.hash = id
333 function DrawNavigator(project, pages) {
334 var menu = document.getElementById('_ui_menu_list');
336 for (const page of pages) {
337 list = list + '<li id="_ui_pglink_' + page.id
338 + '" class="pure-menu-item"><a class="pure-menu-link" onclick="DrawPage(\''+ page.id +'\')" href="#' + page.id + '">'
339 + (page.icon?'<span class="icon">'+page.icon+'</span>':'')
340 + page.title+'</a></li>'
342 menu.innerHTML = list
345 function DrawContacts(contacts) {
346 if (!contacts) return;
347 var contact_list = '<hr><h4 class="pure-u1">Контакты</h4>'
348 for (contact of contacts) {
349 const url = new URL(contact)
351 switch (url.protocol) {
354 ref = '<span class="icon"></span>'+url.hostname
357 ref = '<span class="icon"></span>'+url.pathname
360 ref = '<span class="icon"></span>'+url.pathname
361 contact = 'tg://resolve?domain='+url.pathname
364 ref = '<span class="icon"></span>'+url.pathname
366 contact_list += '<a href="'+contact+'">'+ref+'</a>'
368 var footer = document.getElementById('_ui_contacts');
369 footer.innerHTML = contact_list
372 function DrawUI(ui) {
373 DrawHeader(ui.project)
375 DrawNavigator(ui.project, pages)
376 DrawContacts(ui.project.contacts)
377 var anchor = getAnchor()
381 DrawPage(pages[0].id)
386 ParseJsonQ("/ui", DrawUI);
392 if (!!window.EventSource) {
393 var source = new EventSource('/events');
395 source.onerror = function(e) {
396 if (source.readyState == 2) {
397 setTimeout(initES, 5000);
401 source.addEventListener('keepalive', function(e) {
402 UpdateValues(JSON.parse(e.data));
405 source.addEventListener('update', function(e) {
406 UpdateValues(JSON.parse(e.data));
413 function DrawConfig(cfg) {
418 ParseJsonQ("/config/get", DrawConfig);