1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 /** 6 * @fileoverview 7 * Class to track of connections to and from this computer and display them. 8 */ 9 10 'use strict'; 11 12 /** @suppress {duplicate} */ 13 var remoting = remoting || {}; 14 15 /** @constructor */ 16 remoting.ConnectionHistory = function() { 17 /** @type {HTMLElement} @private */ 18 this.viewAll_ = document.getElementById('history-view-all'); 19 /** @type {HTMLElement} @private */ 20 this.viewOutgoing_ = document.getElementById('history-view-outgoing'); 21 /** @type {HTMLElement} @private */ 22 this.viewIncoming_ = document.getElementById('history-view-incoming'); 23 /** @type {HTMLElement} @private */ 24 this.clear_ = document.getElementById('clear-connection-history'); 25 /** @type {HTMLElement} @private */ 26 this.historyEntries_ = document.getElementById('connection-history-entries'); 27 /** @type {remoting.ConnectionHistory.Filter} @private */ 28 this.filter_ = remoting.ConnectionHistory.Filter.VIEW_ALL; 29 30 /** @type {remoting.ConnectionHistory} */ 31 var that = this; 32 var closeButton = document.getElementById('close-connection-history'); 33 closeButton.addEventListener('click', this.hide.bind(this), false); 34 /** @param {Event} event Event identifying which button was clicked. */ 35 var setFilter = function(event) { that.setFilter_(event.target); }; 36 this.viewAll_.addEventListener('click', setFilter, false); 37 this.viewOutgoing_.addEventListener('click', setFilter, false); 38 this.viewIncoming_.addEventListener('click', setFilter, false); 39 this.clear_.addEventListener('click', this.clearHistory_.bind(this), false); 40 }; 41 42 /** @enum {string} */ 43 remoting.ConnectionHistory.Filter = { 44 VIEW_ALL: 'history-view-all', 45 VIEW_OUTGOING: 'history-view-outgoing', 46 VIEW_INCOMING: 'history-view-incoming' 47 }; 48 49 /** Show the dialog and refresh its contents */ 50 remoting.ConnectionHistory.prototype.show = function() { 51 this.load(); 52 remoting.setMode(remoting.AppMode.HISTORY); 53 }; 54 55 /** Hide the dialog */ 56 remoting.ConnectionHistory.prototype.hide = function() { 57 remoting.setMode(remoting.AppMode.HOME); 58 }; 59 60 /** 61 * A saved entry in the connection history. 62 * @param {Object} object A Javascript object, which may or may not be of the 63 * correct type. 64 * @constructor 65 */ 66 remoting.ConnectionHistory.Entry = function(object) { 67 this.valid = 68 'date' in object && typeof(object['date']) == 'number' && 69 'from' in object && typeof(object['from']) == 'string' && 70 'to' in object && typeof(object['to']) == 'string' && 71 'duration' in object && typeof(object['duration']) == 'number'; 72 if (this.valid) { 73 /** @type {Date} */ 74 this.date = new Date(object['date']); 75 /** @type {string} */ 76 this.from = object['from']; 77 /** @type {string} */ 78 this.to = object['to']; 79 /** @type {number} */ 80 this.duration = object['duration']; 81 } 82 }; 83 84 /** 85 * @return {string} The connection duration, formatted as a string, or 'Not 86 * available' if there is no duration stored. 87 * @private 88 */ 89 remoting.ConnectionHistory.Entry.prototype.durationString_ = function() { 90 var secs = this.duration % 60; 91 var mins = ((this.duration - secs) / 60) % 60; 92 var hours = (this.duration - secs - 60 * mins) / 3600; 93 if (secs < 10) { 94 secs = '0' + secs; 95 } 96 var result = mins + ':' + secs; 97 if (hours > 0) { 98 if (mins < 10) { 99 result = '0' + result; 100 } 101 result = hours + ':' + result; 102 } 103 return result; 104 }; 105 106 /** 107 * @return {{summary: Element, detail: Element}} Two table rows containing the 108 * summary and detail information, respectively, for the connection. 109 */ 110 remoting.ConnectionHistory.Entry.prototype.createTableRows = function() { 111 var summary = /** @type {HTMLElement} */ document.createElement('tr'); 112 summary.classList.add('connection-history-summary'); 113 var zippy = /** @type {HTMLElement} */ document.createElement('td'); 114 zippy.classList.add('zippy'); 115 summary.appendChild(zippy); 116 // TODO(jamiewalch): Find a way of combining date and time such both align 117 // vertically without being considered separate columns, which puts too much 118 // space between them. 119 var date = document.createElement('td'); 120 // TODO(jamiewalch): Use a shorter localized version of the date. 121 date.innerText = this.date.toLocaleDateString(); 122 summary.appendChild(date); 123 var time = document.createElement('td'); 124 time.innerText = this.date.toLocaleTimeString(); 125 summary.appendChild(time); 126 var from = document.createElement('td'); 127 from.innerText = this.from; 128 summary.appendChild(from); 129 var to = document.createElement('td'); 130 to.innerText = this.to; 131 summary.appendChild(to); 132 var duration = document.createElement('td'); 133 duration.innerText = this.durationString_(); 134 summary.appendChild(duration); 135 // TODO(jamiewalch): Fill out the detail row correctly. 136 var detail = /** @type {HTMLElement} */ document.createElement('tr'); 137 detail.classList.add('connection-history-detail'); 138 for (var i = 0; i < summary.childElementCount; ++i) { 139 var td = document.createElement('td'); 140 if (i != 0) { 141 // The inner div allows the details rows to be hidden without changing 142 // the column widths. 143 var div = document.createElement('div'); 144 div.innerText = 'Nothing to see here'; 145 td.appendChild(div); 146 } 147 detail.appendChild(td); 148 } 149 /** @param {HTMLElement} node The summary row. */ 150 var toggleDetail = function(node) { 151 node.classList.toggle('expanded'); 152 }; 153 summary.addEventListener('click', 154 function() { toggleDetail(summary); }, 155 false); 156 detail.addEventListener('click', 157 function() { toggleDetail(summary); }, 158 false); 159 return { 'summary': summary, 'detail': detail }; 160 }; 161 162 /** Refresh the contents of the connection history table */ 163 remoting.ConnectionHistory.prototype.load = function() { 164 // TODO(jamiewalch): Load connection history data when it's available. 165 var history = []; 166 // Remove existing entries from the DOM and repopulate. 167 // TODO(jamiewalch): Enforce the filter. 168 this.historyEntries_.innerText = ''; 169 for (var i in history) { 170 var connection = new remoting.ConnectionHistory.Entry(history[i]); 171 if (connection.valid) { 172 var rows = connection.createTableRows(); 173 this.historyEntries_.appendChild(rows.summary); 174 this.historyEntries_.appendChild(rows.detail); 175 } 176 } 177 }; 178 179 /** 180 * @param {EventTarget} element The element that was clicked. 181 * @private 182 */ 183 remoting.ConnectionHistory.prototype.setFilter_ = function(element) { 184 for (var i in remoting.ConnectionHistory.Filter) { 185 var link = document.getElementById(remoting.ConnectionHistory.Filter[i]); 186 if (element == link) { 187 link.classList.add('no-link'); 188 this.filter_ = /** @type {remoting.ConnectionHistory.Filter} */ (i); 189 } else { 190 link.classList.remove('no-link'); 191 } 192 } 193 }; 194 195 /** 196 * @private 197 */ 198 remoting.ConnectionHistory.prototype.clearHistory_ = function() { 199 // TODO(jamiewalch): Implement once we store users' connection histories. 200 }; 201 202 /** @type {remoting.ConnectionHistory} */ 203 remoting.ConnectionHistory.connectionHistory = null; 204