![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
sample_pir-lights_rgb
webapp/views/index.html@0:7a352727249b, 2017-06-18 (annotated)
- Committer:
- iv123
- Date:
- Sun Jun 18 10:14:56 2017 +0000
- Revision:
- 0:7a352727249b
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
iv123 | 0:7a352727249b | 1 | <!DOCTYPE html> |
iv123 | 0:7a352727249b | 2 | <html> |
iv123 | 0:7a352727249b | 3 | <head> |
iv123 | 0:7a352727249b | 4 | <meta charset="utf-8"> |
iv123 | 0:7a352727249b | 5 | <title>Light System</title> |
iv123 | 0:7a352727249b | 6 | <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'> |
iv123 | 0:7a352727249b | 7 | <link rel="stylesheet" href="/style.css"> |
iv123 | 0:7a352727249b | 8 | <link rel="import" href="/color-picker-element/dist/color-picker.html"> |
iv123 | 0:7a352727249b | 9 | <link rel="manifest" href="/manifest.json"> |
iv123 | 0:7a352727249b | 10 | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> |
iv123 | 0:7a352727249b | 11 | </head> |
iv123 | 0:7a352727249b | 12 | |
iv123 | 0:7a352727249b | 13 | <body> |
iv123 | 0:7a352727249b | 14 | <div id="header"> |
iv123 | 0:7a352727249b | 15 | <a href="/"><img id="logo" src="/ARMmbedLogo.svg"></a> |
iv123 | 0:7a352727249b | 16 | </div> |
iv123 | 0:7a352727249b | 17 | |
iv123 | 0:7a352727249b | 18 | <h1>Lights</h1> |
iv123 | 0:7a352727249b | 19 | |
iv123 | 0:7a352727249b | 20 | <ul id="lights"> |
iv123 | 0:7a352727249b | 21 | {{#devices}} |
iv123 | 0:7a352727249b | 22 | {{> device}} |
iv123 | 0:7a352727249b | 23 | {{/devices}} |
iv123 | 0:7a352727249b | 24 | </ul> |
iv123 | 0:7a352727249b | 25 | |
iv123 | 0:7a352727249b | 26 | <div id="color-picker-overlay" style="display: none"> |
iv123 | 0:7a352727249b | 27 | <h2>Change color</h2> |
iv123 | 0:7a352727249b | 28 | </div> |
iv123 | 0:7a352727249b | 29 | <div id="notification" style="opacity: 0; visibility: hidden;"></div> |
iv123 | 0:7a352727249b | 30 | |
iv123 | 0:7a352727249b | 31 | <script src="/helper-functions.js"></script> |
iv123 | 0:7a352727249b | 32 | <script src="/color-picker.js"></script> |
iv123 | 0:7a352727249b | 33 | <script src="/socket.io/socket.io.js"></script> |
iv123 | 0:7a352727249b | 34 | <script> |
iv123 | 0:7a352727249b | 35 | /*global io getElement updateStatusUi getDeviceName showNotification localStorage */ |
iv123 | 0:7a352727249b | 36 | |
iv123 | 0:7a352727249b | 37 | // Here is how we connect back to the server |
iv123 | 0:7a352727249b | 38 | var socket = io.connect(location.origin); |
iv123 | 0:7a352727249b | 39 | |
iv123 | 0:7a352727249b | 40 | // ==== BEGIN SERVER EVENTS ==== |
iv123 | 0:7a352727249b | 41 | |
iv123 | 0:7a352727249b | 42 | var createDeviceEv, deleteDeviceEv, changeStatusEv, changeColorEv, changeTimeoutEv; |
iv123 | 0:7a352727249b | 43 | |
iv123 | 0:7a352727249b | 44 | // Device came online, add it to the UI |
iv123 | 0:7a352727249b | 45 | socket.on('created-device', createDeviceEv = function(viewModel) { |
iv123 | 0:7a352727249b | 46 | document.querySelector('#lights').insertAdjacentHTML('beforeend', viewModel.html); |
iv123 | 0:7a352727249b | 47 | }); |
iv123 | 0:7a352727249b | 48 | |
iv123 | 0:7a352727249b | 49 | // Device was deleted, remove it from the UI |
iv123 | 0:7a352727249b | 50 | socket.on('deleted-device', deleteDeviceEv = function(endpoint) { |
iv123 | 0:7a352727249b | 51 | var li = getElement(endpoint); |
iv123 | 0:7a352727249b | 52 | li.parentNode.removeChild(li); |
iv123 | 0:7a352727249b | 53 | |
iv123 | 0:7a352727249b | 54 | showNotification(getDeviceName(endpoint, true) + ' was de-registered'); |
iv123 | 0:7a352727249b | 55 | }); |
iv123 | 0:7a352727249b | 56 | |
iv123 | 0:7a352727249b | 57 | // Status of a device was updated |
iv123 | 0:7a352727249b | 58 | socket.on('change-status', changeStatusEv = function(endpoint, status) { |
iv123 | 0:7a352727249b | 59 | updateStatusUi(endpoint, status); |
iv123 | 0:7a352727249b | 60 | }); |
iv123 | 0:7a352727249b | 61 | |
iv123 | 0:7a352727249b | 62 | // Color of a device was updated |
iv123 | 0:7a352727249b | 63 | socket.on('change-color', changeColorEv = function(endpoint, color) { |
iv123 | 0:7a352727249b | 64 | var hex = Number(color).toString(16); |
iv123 | 0:7a352727249b | 65 | getElement(endpoint).querySelector('.color').style.backgroundColor = |
iv123 | 0:7a352727249b | 66 | '#' + '000000'.substring(0, 6 - hex.length) + hex; |
iv123 | 0:7a352727249b | 67 | }); |
iv123 | 0:7a352727249b | 68 | |
iv123 | 0:7a352727249b | 69 | // Timeout of a device was updated |
iv123 | 0:7a352727249b | 70 | socket.on('change-timeout', changeTimeoutEv = function(endpoint, timeout) { |
iv123 | 0:7a352727249b | 71 | getElement(endpoint).querySelector('.change-timeout').textContent = |
iv123 | 0:7a352727249b | 72 | timeout + ' seconds'; |
iv123 | 0:7a352727249b | 73 | }); |
iv123 | 0:7a352727249b | 74 | |
iv123 | 0:7a352727249b | 75 | // When you go offline=>online, server will automatically send current state |
iv123 | 0:7a352727249b | 76 | // So you're always up to date with other clients. |
iv123 | 0:7a352727249b | 77 | socket.on('device-list', function(list) { |
iv123 | 0:7a352727249b | 78 | list.forEach(function(device) { |
iv123 | 0:7a352727249b | 79 | // element not in the UI yet? Create it! |
iv123 | 0:7a352727249b | 80 | if (!getElement(device.endpoint)) { |
iv123 | 0:7a352727249b | 81 | return createDeviceEv(device.view); |
iv123 | 0:7a352727249b | 82 | } |
iv123 | 0:7a352727249b | 83 | |
iv123 | 0:7a352727249b | 84 | // otherwise, update the properties |
iv123 | 0:7a352727249b | 85 | changeStatusEv(device.endpoint, device.view.model.status); |
iv123 | 0:7a352727249b | 86 | changeColorEv(device.endpoint, device.view.model.rawColor); |
iv123 | 0:7a352727249b | 87 | changeTimeoutEv(device.endpoint, device.view.model.timeout); |
iv123 | 0:7a352727249b | 88 | }); |
iv123 | 0:7a352727249b | 89 | |
iv123 | 0:7a352727249b | 90 | // find devices that are still in the UI, but no longer in the list... |
iv123 | 0:7a352727249b | 91 | var validEndpoints = list.map(function(device) { return device.endpoint; }); |
iv123 | 0:7a352727249b | 92 | [].forEach.call(document.querySelectorAll('li[data-endpoint]'), function(li) { |
iv123 | 0:7a352727249b | 93 | if (validEndpoints.indexOf(li.dataset.endpoint) === -1) { |
iv123 | 0:7a352727249b | 94 | deleteDeviceEv(li.dataset.endpoint); |
iv123 | 0:7a352727249b | 95 | } |
iv123 | 0:7a352727249b | 96 | }); |
iv123 | 0:7a352727249b | 97 | |
iv123 | 0:7a352727249b | 98 | }); |
iv123 | 0:7a352727249b | 99 | |
iv123 | 0:7a352727249b | 100 | // ==== END OF SERVER EVENTS ==== |
iv123 | 0:7a352727249b | 101 | |
iv123 | 0:7a352727249b | 102 | |
iv123 | 0:7a352727249b | 103 | |
iv123 | 0:7a352727249b | 104 | // ==== BEGIN UI EVENTS ==== |
iv123 | 0:7a352727249b | 105 | |
iv123 | 0:7a352727249b | 106 | // When someone clicks on an element in the device area... |
iv123 | 0:7a352727249b | 107 | document.querySelector('#lights').addEventListener('click', function(e) { |
iv123 | 0:7a352727249b | 108 | |
iv123 | 0:7a352727249b | 109 | // We look at which endpoint we're clicking on... |
iv123 | 0:7a352727249b | 110 | var parent = e.target; |
iv123 | 0:7a352727249b | 111 | while (e.target.parentElement && !((parent = parent.parentElement).dataset.endpoint)) { |
iv123 | 0:7a352727249b | 112 | // noop |
iv123 | 0:7a352727249b | 113 | } |
iv123 | 0:7a352727249b | 114 | if (!parent.dataset.endpoint) return console.error('Could not find parent for', e.target); |
iv123 | 0:7a352727249b | 115 | |
iv123 | 0:7a352727249b | 116 | var endpoint = parent.dataset.endpoint; |
iv123 | 0:7a352727249b | 117 | |
iv123 | 0:7a352727249b | 118 | // Now we can check which element we clicked on: |
iv123 | 0:7a352727249b | 119 | if (e.target.classList.contains('change-timeout')) { |
iv123 | 0:7a352727249b | 120 | changeTimeout(endpoint, e.target); |
iv123 | 0:7a352727249b | 121 | return false; |
iv123 | 0:7a352727249b | 122 | } |
iv123 | 0:7a352727249b | 123 | |
iv123 | 0:7a352727249b | 124 | if (e.target.classList.contains('change-status')) { |
iv123 | 0:7a352727249b | 125 | changeStatus(endpoint, e.target); |
iv123 | 0:7a352727249b | 126 | return false; |
iv123 | 0:7a352727249b | 127 | } |
iv123 | 0:7a352727249b | 128 | |
iv123 | 0:7a352727249b | 129 | // Names are stored locally... |
iv123 | 0:7a352727249b | 130 | if (e.target.classList.contains('change-endpoint-name')) { |
iv123 | 0:7a352727249b | 131 | var n = prompt('Enter new name'); |
iv123 | 0:7a352727249b | 132 | if (n) { |
iv123 | 0:7a352727249b | 133 | e.target.textContent = n; |
iv123 | 0:7a352727249b | 134 | localStorage.setItem(endpoint + '-name', n); |
iv123 | 0:7a352727249b | 135 | } |
iv123 | 0:7a352727249b | 136 | else if (n === '') { |
iv123 | 0:7a352727249b | 137 | e.target.textContent = endpoint; |
iv123 | 0:7a352727249b | 138 | localStorage.setItem(endpoint + '-name', ''); |
iv123 | 0:7a352727249b | 139 | } |
iv123 | 0:7a352727249b | 140 | return false; |
iv123 | 0:7a352727249b | 141 | } |
iv123 | 0:7a352727249b | 142 | |
iv123 | 0:7a352727249b | 143 | // Click on color => show color picker |
iv123 | 0:7a352727249b | 144 | if (e.target.classList.contains('color')) { |
iv123 | 0:7a352727249b | 145 | var cp = document.querySelector('#color-picker-overlay'); |
iv123 | 0:7a352727249b | 146 | cp.dataset.endpoint = endpoint; |
iv123 | 0:7a352727249b | 147 | cp.style.display = 'flex'; |
iv123 | 0:7a352727249b | 148 | return false; |
iv123 | 0:7a352727249b | 149 | } |
iv123 | 0:7a352727249b | 150 | }); |
iv123 | 0:7a352727249b | 151 | |
iv123 | 0:7a352727249b | 152 | // ==== END UI EVENTS ==== |
iv123 | 0:7a352727249b | 153 | |
iv123 | 0:7a352727249b | 154 | |
iv123 | 0:7a352727249b | 155 | |
iv123 | 0:7a352727249b | 156 | // ==== BEGIN UI ACTIONS ==== |
iv123 | 0:7a352727249b | 157 | |
iv123 | 0:7a352727249b | 158 | function changeTimeout(endpoint, el) { |
iv123 | 0:7a352727249b | 159 | var old = el.textContent.split(' ')[0]; |
iv123 | 0:7a352727249b | 160 | |
iv123 | 0:7a352727249b | 161 | // Ask for a new value and verify that it's a number |
iv123 | 0:7a352727249b | 162 | var v = prompt('Enter a new value for the motion timeout'); |
iv123 | 0:7a352727249b | 163 | if (v === false) return; |
iv123 | 0:7a352727249b | 164 | if (!v || isNaN(v)) { |
iv123 | 0:7a352727249b | 165 | return showNotification('Updating timeout failed: not a number'); |
iv123 | 0:7a352727249b | 166 | } |
iv123 | 0:7a352727249b | 167 | |
iv123 | 0:7a352727249b | 168 | // Update the UI |
iv123 | 0:7a352727249b | 169 | el.textContent = v + ' seconds'; |
iv123 | 0:7a352727249b | 170 | // Send to the server |
iv123 | 0:7a352727249b | 171 | socket.emit('change-timeout', endpoint, Number(v), function(err) { |
iv123 | 0:7a352727249b | 172 | // If it fails, reset to old value and show notification |
iv123 | 0:7a352727249b | 173 | if (err) { |
iv123 | 0:7a352727249b | 174 | el.textContent = old + ' seconds'; |
iv123 | 0:7a352727249b | 175 | showNotification('Updating timeout failed: ' + err); |
iv123 | 0:7a352727249b | 176 | } |
iv123 | 0:7a352727249b | 177 | }); |
iv123 | 0:7a352727249b | 178 | } |
iv123 | 0:7a352727249b | 179 | |
iv123 | 0:7a352727249b | 180 | function changeStatus(endpoint, el) { |
iv123 | 0:7a352727249b | 181 | // get the currently selected value |
iv123 | 0:7a352727249b | 182 | var old = el.parentNode.querySelector('.selected').dataset.action; |
iv123 | 0:7a352727249b | 183 | |
iv123 | 0:7a352727249b | 184 | // update the UI |
iv123 | 0:7a352727249b | 185 | updateStatusUi(endpoint, el.dataset.action); |
iv123 | 0:7a352727249b | 186 | |
iv123 | 0:7a352727249b | 187 | // send to server |
iv123 | 0:7a352727249b | 188 | socket.emit('change-status', endpoint, Number(el.dataset.action), function(err) { |
iv123 | 0:7a352727249b | 189 | // if it fails, reset to old value and show notification |
iv123 | 0:7a352727249b | 190 | if (err) { |
iv123 | 0:7a352727249b | 191 | updateStatusUi(endpoint, old); |
iv123 | 0:7a352727249b | 192 | showNotification('Updating status failed: ' + err); |
iv123 | 0:7a352727249b | 193 | } |
iv123 | 0:7a352727249b | 194 | }); |
iv123 | 0:7a352727249b | 195 | } |
iv123 | 0:7a352727249b | 196 | |
iv123 | 0:7a352727249b | 197 | function changeColor(endpoint, newColor) { |
iv123 | 0:7a352727249b | 198 | var colorEl = getElement(endpoint).querySelector('.color'); |
iv123 | 0:7a352727249b | 199 | var oldHex = Number(colorEl.dataset.value).toString(16); |
iv123 | 0:7a352727249b | 200 | var newHex = Number(newColor).toString(16); |
iv123 | 0:7a352727249b | 201 | |
iv123 | 0:7a352727249b | 202 | if (newColor === 0) return; |
iv123 | 0:7a352727249b | 203 | |
iv123 | 0:7a352727249b | 204 | console.log('new value is', newColor); |
iv123 | 0:7a352727249b | 205 | |
iv123 | 0:7a352727249b | 206 | // Update UI |
iv123 | 0:7a352727249b | 207 | colorEl.style.backgroundColor = '#' + '000000'.substring(0, 6 - newHex.length) + newHex; |
iv123 | 0:7a352727249b | 208 | |
iv123 | 0:7a352727249b | 209 | // Send to server |
iv123 | 0:7a352727249b | 210 | socket.emit('change-color', endpoint, newColor, function(err) { |
iv123 | 0:7a352727249b | 211 | // If all fails, reset back to old color |
iv123 | 0:7a352727249b | 212 | if (err) { |
iv123 | 0:7a352727249b | 213 | colorEl.style.backgroundColor = '#' + '000000'.substring(0, 6 - oldHex.length) + oldHex; |
iv123 | 0:7a352727249b | 214 | showNotification('Updating color failed: ' + err); |
iv123 | 0:7a352727249b | 215 | } |
iv123 | 0:7a352727249b | 216 | }); |
iv123 | 0:7a352727249b | 217 | } |
iv123 | 0:7a352727249b | 218 | |
iv123 | 0:7a352727249b | 219 | // ==== END UI ACTIONS ==== |
iv123 | 0:7a352727249b | 220 | |
iv123 | 0:7a352727249b | 221 | </script> |
iv123 | 0:7a352727249b | 222 | |
iv123 | 0:7a352727249b | 223 | </body> |
iv123 | 0:7a352727249b | 224 | </html> |