OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 // TODO(jhawkins): Use hidden instead of showInline* and display:none. | 5 // TODO(jhawkins): Use hidden instead of showInline* and display:none. |
6 | 6 |
7 /** | 7 /** |
8 * The type of the download object. The definition is based on | 8 * The type of the download object. The definition is based on |
9 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue() | 9 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue() |
10 * @typedef {{by_ext_id: (string|undefined), | 10 * @typedef {{by_ext_id: (string|undefined), |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 */ | 70 */ |
71 function createButton(onclick, value) { | 71 function createButton(onclick, value) { |
72 var button = document.createElement('input'); | 72 var button = document.createElement('input'); |
73 button.type = 'button'; | 73 button.type = 'button'; |
74 button.value = value; | 74 button.value = value; |
75 button.onclick = onclick; | 75 button.onclick = onclick; |
76 return button; | 76 return button; |
77 } | 77 } |
78 | 78 |
79 /////////////////////////////////////////////////////////////////////////////// | 79 /////////////////////////////////////////////////////////////////////////////// |
| 80 // DownloadFocusObserver: |
| 81 |
| 82 /** |
| 83 * @constructor |
| 84 * @implements {cr.ui.FocusRow.Observer} |
| 85 */ |
| 86 function DownloadFocusObserver() {} |
| 87 |
| 88 DownloadFocusObserver.prototype = { |
| 89 /** @override */ |
| 90 onActivate: function(row) {}, |
| 91 |
| 92 /** @override */ |
| 93 onDeactivate: function(row) {}, |
| 94 |
| 95 /** |
| 96 * @param {Element} item The row item to find a a row element for. |
| 97 * @return {Element} |row|'s "active" element. |
| 98 * @override |
| 99 */ |
| 100 getRowElement: function(item) { |
| 101 return findAncestorByClass(item, 'download'); |
| 102 }, |
| 103 |
| 104 /** @override */ |
| 105 onElementIdMiss: function(row, expectedId) { |
| 106 // These are at the same level visually, so focus the first available one if |
| 107 // it exists. |
| 108 var remaining = ['show', 'retry', 'pause', 'resume', 'remove', 'cancel']; |
| 109 if (remaining.indexOf(expectedId) > -1) { |
| 110 for (var i = 0; i < remaining.length; ++i) { |
| 111 if (row.elementIds.indexOf(remaining[i]) > -1) |
| 112 return remaining[i]; |
| 113 } |
| 114 } |
| 115 |
| 116 // Select the first item that is focusable if nothing else worked. |
| 117 return row.elementIds[0]; |
| 118 }, |
| 119 }; |
| 120 |
| 121 /////////////////////////////////////////////////////////////////////////////// |
80 // Downloads | 122 // Downloads |
81 /** | 123 /** |
82 * Class to hold all the information about the visible downloads. | 124 * Class to hold all the information about the visible downloads. |
83 * @constructor | 125 * @constructor |
84 */ | 126 */ |
85 function Downloads() { | 127 function Downloads() { |
86 /** | 128 /** |
87 * @type {!Object.<string, Download>} | 129 * @type {!Object.<string, Download>} |
88 * @private | 130 * @private |
89 */ | 131 */ |
90 this.downloads_ = {}; | 132 this.downloads_ = {}; |
91 this.node_ = $('downloads-display'); | 133 this.node_ = $('downloads-display'); |
92 this.summary_ = $('downloads-summary-text'); | 134 this.summary_ = $('downloads-summary-text'); |
93 this.searchText_ = ''; | 135 this.searchText_ = ''; |
| 136 this.focusGrid_ = new cr.ui.FocusGrid(this.node_, |
| 137 new DownloadFocusObserver()); |
94 | 138 |
95 // Keep track of the dates of the newest and oldest downloads so that we | 139 // Keep track of the dates of the newest and oldest downloads so that we |
96 // know where to insert them. | 140 // know where to insert them. |
97 this.newestTime_ = -1; | 141 this.newestTime_ = -1; |
98 | 142 |
99 // Icon load request queue. | 143 // Icon load request queue. |
100 this.iconLoadQueue_ = []; | 144 this.iconLoadQueue_ = []; |
101 this.isIconLoading_ = false; | 145 this.isIconLoading_ = false; |
102 | 146 |
103 this.progressForeground1_ = new Image(); | 147 this.progressForeground1_ = new Image(); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 var noDownloadsOrResults = $('no-downloads-or-results'); | 213 var noDownloadsOrResults = $('no-downloads-or-results'); |
170 noDownloadsOrResults.textContent = loadTimeData.getString( | 214 noDownloadsOrResults.textContent = loadTimeData.getString( |
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); | 215 this.searchText_ ? 'no_search_results' : 'no_downloads'); |
172 | 216 |
173 var hasDownloads = this.size() > 0; | 217 var hasDownloads = this.size() > 0; |
174 this.node_.hidden = !hasDownloads; | 218 this.node_.hidden = !hasDownloads; |
175 noDownloadsOrResults.hidden = hasDownloads; | 219 noDownloadsOrResults.hidden = hasDownloads; |
176 | 220 |
177 if (loadTimeData.getBoolean('allow_deleting_history')) | 221 if (loadTimeData.getBoolean('allow_deleting_history')) |
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; | 222 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; |
| 223 |
| 224 this.rebuildFocusGrid_(); |
179 }; | 225 }; |
180 | 226 |
181 /** | 227 /** |
| 228 * Determines if element should be focusable. |
| 229 * @param {!Element} element |
| 230 * @return {bool} |
| 231 * @private |
| 232 */ |
| 233 Downloads.shouldFocus_ = function(element) { |
| 234 if (!element) |
| 235 return false; |
| 236 |
| 237 // Hidden elements are not focusable. |
| 238 var style = window.getComputedStyle(element); |
| 239 if (style.visibility == 'hidden' || style.display == 'none') |
| 240 return false; |
| 241 |
| 242 // Verify that all ancestors are focusable. |
| 243 if (element.parentElement) |
| 244 return Downloads.shouldFocus_(element.parentElement); |
| 245 |
| 246 return true; |
| 247 }; |
| 248 |
| 249 /** |
| 250 * Will add an element to |focusRow| if it can be focused. |
| 251 * @param {cr.ui.FocusRow} focusRow The row to add the element to. |
| 252 * @param {Element} element The element to add. |
| 253 * @param {string} elementId The elementId used for selecting in a grid. |
| 254 * @private |
| 255 */ |
| 256 Downloads.prototype.addRowElement_ = function(focusRow, element, elementId) { |
| 257 if (Downloads.shouldFocus_(element)) |
| 258 focusRow.setFocusableElementId(element, elementId); |
| 259 }; |
| 260 |
| 261 /** |
| 262 * Rebuild the focusGrid_ using the elements that each download will have. |
| 263 * @private |
| 264 */ |
| 265 Downloads.prototype.rebuildFocusGrid_ = function() { |
| 266 this.focusGrid_.destroy(); |
| 267 |
| 268 // Keys for downloads are in the reverse order of what is displayed. |
| 269 var keys = Object.keys(this.downloads_); |
| 270 for (var i = keys.length - 1; i >= 0; --i) { |
| 271 var node = this.downloads_[keys[i]]; |
| 272 var focusRow = this.focusGrid_.createRow(); |
| 273 |
| 274 // Add all clickable elements as a row into the grid. |
| 275 this.addRowElement_(focusRow, node.nodeFileLink_, 'name'); |
| 276 this.addRowElement_(focusRow, node.nodeURL_, 'url'); |
| 277 this.addRowElement_(focusRow, node.controlShow_, 'show'); |
| 278 this.addRowElement_(focusRow, node.controlRetry_, 'retry'); |
| 279 this.addRowElement_(focusRow, node.controlPause_, 'pause'); |
| 280 this.addRowElement_(focusRow, node.controlResume_, 'resume'); |
| 281 this.addRowElement_(focusRow, node.controlRemove_, 'remove'); |
| 282 this.addRowElement_(focusRow, node.controlCancel_, 'cancel'); |
| 283 |
| 284 // These buttons are mutually exclusive, but they are visually the same. |
| 285 this.addRowElement_(focusRow, node.malwareSave_, 'save'); |
| 286 this.addRowElement_(focusRow, node.dangerSave_, 'save'); |
| 287 this.addRowElement_(focusRow, node.malwareDiscard_, 'discard'); |
| 288 this.addRowElement_(focusRow, node.dangerDiscard_, 'discard'); |
| 289 |
| 290 this.addRowElement_(focusRow, node.controlByExtensionLink_, 'extension'); |
| 291 |
| 292 this.focusGrid_.addRow(focusRow); |
| 293 } |
| 294 }; |
| 295 |
| 296 /** |
182 * Returns the number of downloads in the model. Used by tests. | 297 * Returns the number of downloads in the model. Used by tests. |
183 * @return {number} Returns the number of downloads shown on the page. | 298 * @return {number} Returns the number of downloads shown on the page. |
184 */ | 299 */ |
185 Downloads.prototype.size = function() { | 300 Downloads.prototype.size = function() { |
186 return Object.keys(this.downloads_).length; | 301 return Object.keys(this.downloads_).length; |
187 }; | 302 }; |
188 | 303 |
189 /** | 304 /** |
190 * Called whenever the downloads lists items have changed (either by being | 305 * Called whenever the downloads lists items have changed (either by being |
191 * updated, added, or removed). | 306 * updated, added, or removed). |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
978 if (Date.now() - start > 50) { | 1093 if (Date.now() - start > 50) { |
979 clearTimeout(resultsTimeout); | 1094 clearTimeout(resultsTimeout); |
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); | 1095 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); |
981 break; | 1096 break; |
982 } | 1097 } |
983 } | 1098 } |
984 } | 1099 } |
985 | 1100 |
986 // Add handlers to HTML elements. | 1101 // Add handlers to HTML elements. |
987 window.addEventListener('DOMContentLoaded', load); | 1102 window.addEventListener('DOMContentLoaded', load); |
OLD | NEW |