| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var ClientRenderer = (function() { | 5 var ClientRenderer = (function() { |
| 6 var ClientRenderer = function() { | 6 var ClientRenderer = function() { |
| 7 this.playerListElement = document.getElementById('player-list'); | 7 this.playerListElement = document.getElementById('player-list'); |
| 8 this.audioStreamListElement = document.getElementById('audio-stream-list'); | 8 this.propertiesTable = |
| 9 this.propertiesTable = document.getElementById('property-table'); | 9 document.getElementById('property-table').querySelector('tbody'); |
| 10 this.logTable = document.getElementById('log'); | 10 this.logTable = document.getElementById('log').querySelector('tbody'); |
| 11 this.graphElement = document.getElementById('graphs'); | 11 this.graphElement = document.getElementById('graphs'); |
| 12 | 12 |
| 13 this.selectedPlayer = null; | 13 this.selectedPlayer = null; |
| 14 this.selectedStream = null; | 14 this.selectedAudioComponentType = null; |
| 15 this.selectedAudioComponentId = null; |
| 16 this.selectedAudioCompontentData = null; |
| 15 | 17 |
| 16 this.selectedPlayerLogIndex = 0; | 18 this.selectedPlayerLogIndex = 0; |
| 17 | 19 |
| 18 this.filterFunction = function() { return true; }; | 20 this.filterFunction = function() { return true; }; |
| 19 this.filterText = document.getElementById('filter-text'); | 21 this.filterText = document.getElementById('filter-text'); |
| 20 this.filterText.onkeyup = this.onTextChange_.bind(this); | 22 this.filterText.onkeyup = this.onTextChange_.bind(this); |
| 21 | 23 |
| 22 this.bufferCanvas = document.createElement('canvas'); | 24 this.bufferCanvas = document.createElement('canvas'); |
| 23 this.bufferCanvas.width = media.BAR_WIDTH; | 25 this.bufferCanvas.width = media.BAR_WIDTH; |
| 24 this.bufferCanvas.height = media.BAR_HEIGHT; | 26 this.bufferCanvas.height = media.BAR_HEIGHT; |
| 25 | 27 |
| 26 this.clipboardTextarea = document.getElementById('clipboard-textarea'); | 28 this.clipboardTextarea = document.getElementById('clipboard-textarea'); |
| 27 this.clipboardButton = document.getElementById('copy-button'); | 29 this.clipboardButton = document.getElementById('copy-button'); |
| 28 this.clipboardButton.onclick = this.copyToClipboard_.bind(this); | 30 this.clipboardButton.onclick = this.copyToClipboard_.bind(this); |
| 31 |
| 32 this.hiddenKeys = ['component_id', 'component_type', 'owner_id']; |
| 29 }; | 33 }; |
| 30 | 34 |
| 31 function removeChildren(element) { | 35 function removeChildren(element) { |
| 32 while (element.hasChildNodes()) { | 36 while (element.hasChildNodes()) { |
| 33 element.removeChild(element.lastChild); | 37 element.removeChild(element.lastChild); |
| 34 } | 38 } |
| 35 }; | 39 }; |
| 36 | 40 |
| 37 function createButton(text, select_cb) { | 41 function createButton(text, select_cb) { |
| 38 var button = document.createElement('button'); | 42 var button = document.createElement('button'); |
| 39 | 43 |
| 40 button.appendChild(document.createTextNode(text)); | 44 button.appendChild(document.createTextNode(text)); |
| 41 button.onclick = function() { | 45 button.onclick = function() { |
| 42 select_cb(); | 46 select_cb(); |
| 43 }; | 47 }; |
| 44 | 48 |
| 45 return button; | 49 return button; |
| 46 }; | 50 }; |
| 47 | 51 |
| 48 ClientRenderer.prototype = { | 52 ClientRenderer.prototype = { |
| 49 audioStreamAdded: function(audioStreams, audioStreamAdded) { | 53 /** |
| 50 this.redrawAudioStreamList_(audioStreams); | 54 * Called when an audio component is added to the collection. |
| 51 }, | 55 * @param componentType Integer AudioComponent enum value; must match values |
| 56 * from the AudioLogFactory::AudioComponent enum. |
| 57 * @param components The entire map of components (name -> dict). |
| 58 */ |
| 59 audioComponentAdded: function(componentType, components) { |
| 60 this.redrawAudioComponentList_(componentType, components); |
| 52 | 61 |
| 53 audioStreamUpdated: function(audioStreams, stream, key, value) { | 62 // Redraw the component if it's currently selected. |
| 54 if (stream === this.selectedStream) { | 63 if (this.selectedAudioComponentType == componentType && |
| 55 this.drawProperties_(stream); | 64 this.selectedAudioComponentId && |
| 65 this.selectedAudioComponentId in components) { |
| 66 this.selectAudioComponent_( |
| 67 componentType, this.selectedAudioComponentId, |
| 68 components[this.selectedAudioComponentId]); |
| 56 } | 69 } |
| 57 }, | 70 }, |
| 58 | 71 |
| 59 audioStreamRemoved: function(audioStreams, audioStreamRemoved) { | 72 /** |
| 60 this.redrawAudioStreamList_(audioStreams); | 73 * Called when an audio component is removed from the collection. |
| 74 * @param componentType Integer AudioComponent enum value; must match values |
| 75 * from the AudioLogFactory::AudioComponent enum. |
| 76 * @param components The entire map of components (name -> dict). |
| 77 */ |
| 78 audioComponentRemoved: function(componentType, components) { |
| 79 this.redrawAudioComponentList_(componentType, components); |
| 80 |
| 81 // Clear the component if it was previously currently selected. |
| 82 if (this.selectedAudioComponentType == componentType && |
| 83 !(this.selectedAudioComponentId in components)) { |
| 84 this.selectAudioComponent_(null, null, {}); |
| 85 } |
| 61 }, | 86 }, |
| 62 | 87 |
| 63 /** | 88 /** |
| 64 * Called when a player is added to the collection. | 89 * Called when a player is added to the collection. |
| 65 * @param players The entire map of id -> player. | 90 * @param players The entire map of id -> player. |
| 66 * @param player_added The player that is added. | 91 * @param player_added The player that is added. |
| 67 */ | 92 */ |
| 68 playerAdded: function(players, playerAdded) { | 93 playerAdded: function(players, playerAdded) { |
| 69 this.redrawPlayerList_(players); | 94 this.redrawPlayerList_(players); |
| 70 }, | 95 }, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 89 if (player === this.selectedPlayer) { | 114 if (player === this.selectedPlayer) { |
| 90 this.drawProperties_(player.properties); | 115 this.drawProperties_(player.properties); |
| 91 this.drawLog_(); | 116 this.drawLog_(); |
| 92 this.drawGraphs_(); | 117 this.drawGraphs_(); |
| 93 } | 118 } |
| 94 if (key === 'name' || key === 'url') { | 119 if (key === 'name' || key === 'url') { |
| 95 this.redrawPlayerList_(players); | 120 this.redrawPlayerList_(players); |
| 96 } | 121 } |
| 97 }, | 122 }, |
| 98 | 123 |
| 99 redrawAudioStreamList_: function(streams) { | 124 redrawAudioComponentList_: function(componentType, components) { |
| 100 removeChildren(this.audioStreamListElement); | 125 function redrawList(renderer, baseName, element) { |
| 126 var fragment = document.createDocumentFragment(); |
| 127 for (id in components) { |
| 128 var li = document.createElement('li'); |
| 129 li.appendChild(createButton( |
| 130 baseName + ' ' + id, renderer.selectAudioComponent_.bind( |
| 131 renderer, componentType, id, components[id]))); |
| 132 fragment.appendChild(li); |
| 133 } |
| 134 removeChildren(element); |
| 135 element.appendChild(fragment); |
| 136 } |
| 101 | 137 |
| 102 for (id in streams) { | 138 switch (componentType) { |
| 103 var li = document.createElement('li'); | 139 case 0: |
| 104 li.appendChild(createButton( | 140 redrawList(this, 'Controller', document.getElementById( |
| 105 id, this.selectAudioStream_.bind(this, streams[id]))); | 141 'audio-input-controller-list')); |
| 106 this.audioStreamListElement.appendChild(li); | 142 break; |
| 143 case 1: |
| 144 redrawList(this, 'Controller', document.getElementById( |
| 145 'audio-output-controller-list')); |
| 146 break; |
| 147 case 2: |
| 148 redrawList(this, 'Stream', document.getElementById( |
| 149 'audio-output-stream-list')); |
| 150 break; |
| 151 default: |
| 152 break; |
| 107 } | 153 } |
| 108 }, | 154 }, |
| 109 | 155 |
| 110 selectAudioStream_: function(audioStream) { | 156 selectAudioComponent_: function(componentType, componentId, componentData) { |
| 111 this.selectedStream = audioStream; | |
| 112 this.selectedPlayer = null; | 157 this.selectedPlayer = null; |
| 113 this.drawProperties_(audioStream); | 158 this.selectedAudioComponentType = componentType; |
| 114 removeChildren(this.logTable.querySelector('tbody')); | 159 this.selectedAudioComponentId = componentId; |
| 160 this.selectedAudioCompontentData = componentData; |
| 161 this.drawProperties_(componentData); |
| 162 removeChildren(this.logTable); |
| 115 removeChildren(this.graphElement); | 163 removeChildren(this.graphElement); |
| 116 }, | 164 }, |
| 117 | 165 |
| 118 redrawPlayerList_: function(players) { | 166 redrawPlayerList_: function(players) { |
| 119 removeChildren(this.playerListElement); | 167 var fragment = document.createDocumentFragment(); |
| 120 | |
| 121 for (id in players) { | 168 for (id in players) { |
| 122 var li = document.createElement('li'); | |
| 123 var player = players[id]; | 169 var player = players[id]; |
| 124 var usableName = player.properties.name || | 170 var usableName = player.properties.name || |
| 125 player.properties.url || | 171 player.properties.url || |
| 126 'player ' + player.id; | 172 'Player ' + player.id; |
| 127 | 173 |
| 174 var li = document.createElement('li'); |
| 128 li.appendChild(createButton( | 175 li.appendChild(createButton( |
| 129 usableName, this.selectPlayer_.bind(this, player))); | 176 usableName, this.selectPlayer_.bind(this, player))); |
| 130 this.playerListElement.appendChild(li); | 177 fragment.appendChild(li); |
| 131 } | 178 } |
| 179 removeChildren(this.playerListElement); |
| 180 this.playerListElement.appendChild(fragment); |
| 132 }, | 181 }, |
| 133 | 182 |
| 134 selectPlayer_: function(player) { | 183 selectPlayer_: function(player) { |
| 135 this.selectedPlayer = player; | 184 this.selectedPlayer = player; |
| 136 this.selectedPlayerLogIndex = 0; | 185 this.selectedPlayerLogIndex = 0; |
| 137 this.selectedStream = null; | 186 this.selectedAudioComponentType = null; |
| 187 this.selectedAudioComponentId = null; |
| 188 this.selectedAudioCompontentData = null; |
| 138 this.drawProperties_(player.properties); | 189 this.drawProperties_(player.properties); |
| 139 | 190 |
| 140 removeChildren(this.logTable.querySelector('tbody')); | 191 removeChildren(this.logTable); |
| 141 removeChildren(this.graphElement); | 192 removeChildren(this.graphElement); |
| 142 this.drawLog_(); | 193 this.drawLog_(); |
| 143 this.drawGraphs_(); | 194 this.drawGraphs_(); |
| 144 }, | 195 }, |
| 145 | 196 |
| 146 drawProperties_: function(propertyMap) { | 197 drawProperties_: function(propertyMap) { |
| 147 removeChildren(this.propertiesTable); | 198 removeChildren(this.propertiesTable); |
| 148 | |
| 149 var sortedKeys = Object.keys(propertyMap).sort(); | 199 var sortedKeys = Object.keys(propertyMap).sort(); |
| 150 for (var i = 0; i < sortedKeys.length; ++i) { | 200 for (var i = 0; i < sortedKeys.length; ++i) { |
| 151 var key = sortedKeys[i]; | 201 var key = sortedKeys[i]; |
| 202 if (this.hiddenKeys.indexOf(key) >= 0) |
| 203 continue; |
| 204 |
| 152 var value = propertyMap[key]; | 205 var value = propertyMap[key]; |
| 153 | |
| 154 var row = this.propertiesTable.insertRow(-1); | 206 var row = this.propertiesTable.insertRow(-1); |
| 155 var keyCell = row.insertCell(-1); | 207 var keyCell = row.insertCell(-1); |
| 156 var valueCell = row.insertCell(-1); | 208 var valueCell = row.insertCell(-1); |
| 157 | 209 |
| 158 keyCell.appendChild(document.createTextNode(key)); | 210 keyCell.appendChild(document.createTextNode(key)); |
| 159 valueCell.appendChild(document.createTextNode(value)); | 211 valueCell.appendChild(document.createTextNode(value)); |
| 160 } | 212 } |
| 161 }, | 213 }, |
| 162 | 214 |
| 163 appendEventToLog_: function(event) { | 215 appendEventToLog_: function(event) { |
| 164 if (this.filterFunction(event.key)) { | 216 if (this.filterFunction(event.key)) { |
| 165 var row = this.logTable.querySelector('tbody').insertRow(-1); | 217 var row = this.logTable.insertRow(-1); |
| 166 | 218 |
| 167 row.insertCell(-1).appendChild(document.createTextNode( | 219 var timestampCell = row.insertCell(-1); |
| 220 timestampCell.classList.add('timestamp'); |
| 221 timestampCell.appendChild(document.createTextNode( |
| 168 util.millisecondsToString(event.time))); | 222 util.millisecondsToString(event.time))); |
| 169 row.insertCell(-1).appendChild(document.createTextNode(event.key)); | 223 row.insertCell(-1).appendChild(document.createTextNode(event.key)); |
| 170 row.insertCell(-1).appendChild(document.createTextNode(event.value)); | 224 row.insertCell(-1).appendChild(document.createTextNode(event.value)); |
| 171 } | 225 } |
| 172 }, | 226 }, |
| 173 | 227 |
| 174 drawLog_: function() { | 228 drawLog_: function() { |
| 175 var toDraw = this.selectedPlayer.allEvents.slice( | 229 var toDraw = this.selectedPlayer.allEvents.slice( |
| 176 this.selectedPlayerLogIndex); | 230 this.selectedPlayerLogIndex); |
| 177 toDraw.forEach(this.appendEventToLog_.bind(this)); | 231 toDraw.forEach(this.appendEventToLog_.bind(this)); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 var middle = current * scale_factor; | 296 var middle = current * scale_factor; |
| 243 var right = end * scale_factor; | 297 var right = end * scale_factor; |
| 244 | 298 |
| 245 ctx.fillStyle = '#a0a'; | 299 ctx.fillStyle = '#a0a'; |
| 246 ctx.fillRect(left, 0, middle - left, height); | 300 ctx.fillRect(left, 0, middle - left, height); |
| 247 ctx.fillStyle = '#aa0'; | 301 ctx.fillStyle = '#aa0'; |
| 248 ctx.fillRect(middle, 0, right - middle, height); | 302 ctx.fillRect(middle, 0, right - middle, height); |
| 249 }, | 303 }, |
| 250 | 304 |
| 251 copyToClipboard_: function() { | 305 copyToClipboard_: function() { |
| 252 var properties = this.selectedStream || | 306 var properties = this.selectedAudioCompontentData || |
| 253 this.selectedPlayer.properties || false; | 307 this.selectedPlayer.properties || false; |
| 254 if (!properties) { | 308 if (!properties) { |
| 255 return; | 309 return; |
| 256 } | 310 } |
| 257 var stringBuffer = []; | 311 var stringBuffer = []; |
| 258 | 312 |
| 259 for (var key in properties) { | 313 for (var key in properties) { |
| 260 var value = properties[key]; | 314 var value = properties[key]; |
| 261 stringBuffer.push(key.toString()); | 315 stringBuffer.push(key.toString()); |
| 262 stringBuffer.push(': '); | 316 stringBuffer.push(': '); |
| 263 stringBuffer.push(value.toString()); | 317 stringBuffer.push(value.toString()); |
| 264 stringBuffer.push('\n'); | 318 stringBuffer.push('\n'); |
| 265 } | 319 } |
| 266 | 320 |
| 267 this.clipboardTextarea.value = stringBuffer.join(''); | 321 this.clipboardTextarea.value = stringBuffer.join(''); |
| 268 this.clipboardTextarea.classList.remove('hidden'); | 322 this.clipboardTextarea.classList.remove('hiddenClipboard'); |
| 269 this.clipboardTextarea.focus(); | 323 this.clipboardTextarea.focus(); |
| 270 this.clipboardTextarea.select(); | 324 this.clipboardTextarea.select(); |
| 271 | 325 |
| 272 // The act of copying anything from the textarea gets canceled | 326 // Hide the clipboard element when it loses focus. |
| 273 // if the element in question gets the class 'hidden' (which contains the | 327 this.clipboardTextarea.onblur = function(event) { |
| 274 // css property display:none) before the event is finished. For this, it | |
| 275 // is necessary put the property setting on the event loop to be executed | |
| 276 // after the copy has taken place. | |
| 277 this.clipboardTextarea.oncopy = function(event) { | |
| 278 setTimeout(function(element) { | 328 setTimeout(function(element) { |
| 279 event.target.classList.add('hidden'); | 329 event.target.classList.add('hiddenClipboard'); |
| 280 }, 0); | 330 }, 0); |
| 281 }; | 331 }; |
| 282 }, | 332 }, |
| 283 | 333 |
| 284 onTextChange_: function(event) { | 334 onTextChange_: function(event) { |
| 285 var text = this.filterText.value.toLowerCase(); | 335 var text = this.filterText.value.toLowerCase(); |
| 286 var parts = text.split(',').map(function(part) { | 336 var parts = text.split(',').map(function(part) { |
| 287 return part.trim(); | 337 return part.trim(); |
| 288 }).filter(function(part) { | 338 }).filter(function(part) { |
| 289 return part.trim().length > 0; | 339 return part.trim().length > 0; |
| 290 }); | 340 }); |
| 291 | 341 |
| 292 this.filterFunction = function(text) { | 342 this.filterFunction = function(text) { |
| 293 text = text.toLowerCase(); | 343 text = text.toLowerCase(); |
| 294 return parts.length === 0 || parts.some(function(part) { | 344 return parts.length === 0 || parts.some(function(part) { |
| 295 return text.indexOf(part) != -1; | 345 return text.indexOf(part) != -1; |
| 296 }); | 346 }); |
| 297 }; | 347 }; |
| 298 | 348 |
| 299 if (this.selectedPlayer) { | 349 if (this.selectedPlayer) { |
| 300 removeChildren(this.logTable.querySelector('tbody')); | 350 removeChildren(this.logTable); |
| 301 this.selectedPlayerLogIndex = 0; | 351 this.selectedPlayerLogIndex = 0; |
| 302 this.drawLog_(); | 352 this.drawLog_(); |
| 303 } | 353 } |
| 304 }, | 354 }, |
| 305 }; | 355 }; |
| 306 | 356 |
| 307 return ClientRenderer; | 357 return ClientRenderer; |
| 308 })(); | 358 })(); |
| OLD | NEW |