var socket; function load() { socket = init_websocket(); Object.entries(init_state).forEach(([device_id, sub_devs]) => { let device = document.querySelector('#' + device_id); Object.entries(sub_devs).forEach(([sub_device_id, state]) => { let sub_dev = device.querySelector('.' + sub_device_id); let svg = sub_dev.querySelector('object').getSVGDocument().firstElementChild; if (state) { svg.classList.remove('off'); svg.classList.add('on'); } }); }); document.querySelectorAll('input[type=color]').forEach((led_input) => { led_input.onchange = function(event) { event.target.parentElement.style.backgroundColor = event.target.value; } }); } /* Websocket setup */ function init_websocket() { let socket = new WebSocket('wss://' + window.location.hostname + ws_uri); socket._send = socket.send; socket.send = function(event_title, data) { data = JSON.stringify({event: event_title, data: data}); if (socket.readyState == 0) { console.log("Socket is still opening!"); return; } socket._send(data); } socket.onmessage = onmessage; socket.onclose = onclose; socket.onerror = onerror; socket.events = {}; socket.events['toggle_outlet'] = toggle_outlet_recv; socket.events['edit_field'] = edit_field_recv; socket.events['new_device'] = new_device_recv; socket.events['lock_device'] = lock_device_recv; socket.events['delete_device'] = delete_device_recv; return socket; } function onmessage (e) { let data = JSON.parse(e.data); let event = data.event; data = data.data; if (!data.ok) { throw new Error("Socket error: event = " + event +", error = " + data.error); } if (socket.events[event] === undefined) { console.log("Unknown socket event: " + event); return; } socket.events[event](data); } function onclose(e) { if (e.wasClean) { return; } // no need to reconnect console.log(e); console.log('Websocket lost connection to server. Re-trying...'); socket = init_websocket(); } function onerror(e) { console.log("Websocket error!") console.log(e); } /* Websocket receive */ function toggle_outlet_recv(data) { let device = document.querySelector('#' + data.device_id); let sub_device = device.querySelector('.' + data.sub_device_id); let svg = sub_device.querySelector('.outlet_image').getSVGDocument().firstChild; if (data.state === true) { svg.classList.remove('off'); svg.classList.add('on'); } else { svg.classList.remove('on'); svg.classList.add('off'); } } function edit_field_recv(data) { let device = document.querySelector('#' + data.device_id); if (data.sub_device_id) { device = device.querySelector('.' + data.sub_device_id); } let field = device.querySelector('.' + data.field); let span = document.createElement('span'); span.innerText = data['value']; span.className = 'field_value'; field.firstElementChild.replaceWith(span); let edit = document.createElement('span'); edit.innerHTML = ''; edit.className = 'edit font-awesome'; edit.setAttribute('onclick', 'edit_field(this.parentElement)'); field.children[1].replaceWith(edit); } function new_device_recv(data) { if (data.device_type == 'RelayDevice') { var template = document.querySelector('#RelayDevice_template'); } else { return; } let node = document.importNode(template.content, true); node.querySelector('.id').querySelector('.field_value').textContent = data.device_id; document.querySelector('#devices').appendChild(node); let children = document.querySelector('#devices').children; children[children.length - 1].id = data.device_id; } function lock_device_recv(data) { let device = document.querySelector('#' + data.device_id); let fields = device.querySelectorAll('.editable'); if (data.locked) { fields.forEach(function(field) { field.querySelector('.edit').remove(); }); device.querySelector('.id').querySelector('.lock').remove(); device.querySelector('.id').querySelector('.delete').remove(); let unlock = document.createElement('span'); unlock.innerHTML = ''; unlock.className = 'unlock font-awesome'; unlock.setAttribute('onclick', 'unlock_device(this.parentElement.parentElement)'); device.querySelector('.id').appendChild(unlock); } else { fields.forEach(function(field) { let edit = document.createElement('span'); edit.innerHTML = ''; edit.className = 'edit font-awesome'; edit.setAttribute('onclick', 'edit_field(this.parentElement)'); field.appendChild(edit); }); device.querySelector('.id').querySelector('.unlock').remove(); let delete_elem = document.createElement('span'); delete_elem.innerHTML = ''; delete_elem.className = 'delete font-awesome'; delete_elem.setAttribute('onclick', 'delete_device(this.parentElement.parentElement)'); device.querySelector('.id').appendChild(delete_elem); let lock = document.createElement('span'); lock.innerHTML = ''; lock.className = 'lock font-awesome'; lock.setAttribute('onclick', 'lock_device(this.parentElement.parentElement)'); device.querySelector('.id').appendChild(lock); } } function delete_device_recv(data) { let device = document.querySelector('#' + data.device_id); device.remove() } /* Websocket send */ function toggle_outlet(svg) { let sub_dev = get_object_from_svg(svg).parentElement; let data = { device_id: sub_dev.parentElement.parentElement.id, sub_device_id: sub_dev.querySelector('.id').innerText, }; socket.send('toggle_outlet', data); } function save_field(field) { let value = field.firstElementChild.value; let device_id = field.parentElement.id; let sub_device_id; if (field.parentElement.className.includes('sub_device')) { sub_device_id = field.parentElement.children[0].textContent; device_id = field.parentElement.parentElement.parentElement.id; } else { sub_device_id = ''; } let data = { device_id: device_id, sub_device_id: sub_device_id, field: field.classList[0], value: value }; socket.send('edit_field', data); } function new_device() { let data = { device_type: 'RelayDevice', }; socket.send('new_device', data); } function lock_device(device) { if (device.querySelector('.save')) { return; } let data = { device_id: device.id, locked: true, }; socket.send('lock_device', data); } function unlock_device(device) { let data = { device_id: device.id, locked: false, }; socket.send('lock_device', data); } function delete_device(device) { if (!window.confirm("Are you sure you want to delete this device?")) { return; } let data = { device_id: device.id, }; socket.send('delete_device', data); } /* DOM */ function edit_field(field) { let value = field.firstElementChild.innerText; let input = document.createElement('input'); input.value = value; field.firstElementChild.replaceWith(input); let save = document.createElement('span'); save.innerHTML = ''; save.className = 'save font-awesome'; save.setAttribute('onclick', 'save_field(this.parentElement)'); field.children[1].replaceWith(save); } /* Misc */ function get_object_from_svg(svg) { let all_objects = document.getElementsByTagName("object"); for (let i=0; i < all_objects.length; i++) { if (svg === all_objects[i].getSVGDocument().firstElementChild) { return all_objects[i]; } } return null; }