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 // DownloadFocusRow: |
| 81 |
| 82 /** |
| 83 * Provides an implementation for a single column grid. |
| 84 * @param {Node} boundary Focus events are ignored outside of this node. |
| 85 * @param {Download} node The Download representing this row. |
| 86 * @extends {cr.ui.FocusRow} |
| 87 */ |
| 88 DownloadFocusRow = function(boundary, node) { |
| 89 cr.ui.FocusRow.call(this, boundary, node.node); |
| 90 |
| 91 // Add all clickable elements as a row into the grid. |
| 92 this.addFocusRow_(node.nodeFileLink_, 'name'); |
| 93 this.addFocusRow_(node.nodeURL_, 'url'); |
| 94 this.addFocusRow_(node.controlShow_, 'show'); |
| 95 this.addFocusRow_(node.controlRetry_, 'retry'); |
| 96 this.addFocusRow_(node.controlPause_, 'pause'); |
| 97 this.addFocusRow_(node.controlResume_, 'resume'); |
| 98 this.addFocusRow_(node.controlRemove_, 'remove'); |
| 99 this.addFocusRow_(node.controlCancel_, 'cancel'); |
| 100 |
| 101 // Only one set of these two buttons will be added to a download row at a |
| 102 // time. They have the same type so that focus is handled well in case |
| 103 // there is a dangerous download right next to a malicious download. |
| 104 this.addFocusRow_(node.malwareSave_, 'save'); |
| 105 this.addFocusRow_(node.malwareDiscard_, 'discard'); |
| 106 this.addFocusRow_(node.dangerSave_, 'save'); |
| 107 this.addFocusRow_(node.dangerDiscard_, 'discard'); |
| 108 |
| 109 this.addFocusRow_(node.controlByExtensionLink_, 'extension'); |
| 110 }; |
| 111 |
| 112 DownloadFocusRow.prototype = { |
| 113 __proto__: cr.ui.FocusRow.prototype, |
| 114 |
| 115 /** @override */ |
| 116 getEquivalentElement: function(element) { |
| 117 if (this.contains(element)) |
| 118 return element; |
| 119 |
| 120 // All elements default to another element with the same type. |
| 121 var query = '[column-type="' + element.getAttribute('column-type') + '"]'; |
| 122 var ret = this.getMatch(query); |
| 123 |
| 124 // The following element types are at the same UI level. |
| 125 if (!ret) { |
| 126 switch (element.getAttribute('column-type')) { |
| 127 case ('show'): |
| 128 case ('retry'): |
| 129 case ('pause'): |
| 130 case ('resume'): |
| 131 case ('remove'): |
| 132 case ('cancel'): |
| 133 ret = this.getMatch('[column-type="show"]') || |
| 134 this.getMatch('[column-type="retry"]') || |
| 135 this.getMatch('[column-type="pause"]') || |
| 136 this.getMatch('[column-type="resume"]') || |
| 137 this.getMatch('[column-type="remove"]') || |
| 138 this.getMatch('[column-type="cancel"]'); |
| 139 break; |
| 140 } |
| 141 } |
| 142 |
| 143 // Any other miss should return the first rowElement. |
| 144 return ret || this.rowElements[0]; |
| 145 }, |
| 146 |
| 147 /** |
| 148 * Add an element if it exists in this FocusRow and is focusable. |
| 149 * @param {Element} element The element that should be added. |
| 150 * @param {string} type The type to use for the element. |
| 151 * @private |
| 152 */ |
| 153 addFocusRow_: function(element, type) { |
| 154 if (this.shouldFocus_(element)) { |
| 155 this.setFocusableElement(element); |
| 156 element.setAttribute('column-type', type); |
| 157 } |
| 158 }, |
| 159 |
| 160 /** |
| 161 * Determines if element should be focusable. |
| 162 * @param {!Element} element |
| 163 * @return {bool} |
| 164 * @private |
| 165 */ |
| 166 shouldFocus_: function(element) { |
| 167 if (!element) |
| 168 return false; |
| 169 |
| 170 // Hidden elements are not focusable. |
| 171 var style = window.getComputedStyle(element); |
| 172 if (style.visibility == 'hidden' || style.display == 'none') |
| 173 return false; |
| 174 |
| 175 // Verify that all ancestors are focusable. This is necessary because of the |
| 176 // case where a node has display set to something other than 'none', but it |
| 177 // has an ancestor with display == 'none'. |
| 178 if (element.parentElement) |
| 179 return this.shouldFocus_(element.parentElement); |
| 180 |
| 181 return true; |
| 182 }, |
| 183 }; |
| 184 |
| 185 /////////////////////////////////////////////////////////////////////////////// |
80 // Downloads | 186 // Downloads |
81 /** | 187 /** |
82 * Class to hold all the information about the visible downloads. | 188 * Class to hold all the information about the visible downloads. |
83 * @constructor | 189 * @constructor |
84 */ | 190 */ |
85 function Downloads() { | 191 function Downloads() { |
86 /** | 192 /** |
87 * @type {!Object.<string, Download>} | 193 * @type {!Object.<string, Download>} |
88 * @private | 194 * @private |
89 */ | 195 */ |
90 this.downloads_ = {}; | 196 this.downloads_ = {}; |
91 this.node_ = $('downloads-display'); | 197 this.node_ = $('downloads-display'); |
92 this.summary_ = $('downloads-summary-text'); | 198 this.summary_ = $('downloads-summary-text'); |
93 this.searchText_ = ''; | 199 this.searchText_ = ''; |
| 200 this.focusGrid_ = new cr.ui.FocusGrid(); |
94 | 201 |
95 // Keep track of the dates of the newest and oldest downloads so that we | 202 // Keep track of the dates of the newest and oldest downloads so that we |
96 // know where to insert them. | 203 // know where to insert them. |
97 this.newestTime_ = -1; | 204 this.newestTime_ = -1; |
98 | 205 |
99 // Icon load request queue. | 206 // Icon load request queue. |
100 this.iconLoadQueue_ = []; | 207 this.iconLoadQueue_ = []; |
101 this.isIconLoading_ = false; | 208 this.isIconLoading_ = false; |
102 | 209 |
103 this.progressForeground1_ = new Image(); | 210 this.progressForeground1_ = new Image(); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 var noDownloadsOrResults = $('no-downloads-or-results'); | 276 var noDownloadsOrResults = $('no-downloads-or-results'); |
170 noDownloadsOrResults.textContent = loadTimeData.getString( | 277 noDownloadsOrResults.textContent = loadTimeData.getString( |
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); | 278 this.searchText_ ? 'no_search_results' : 'no_downloads'); |
172 | 279 |
173 var hasDownloads = this.size() > 0; | 280 var hasDownloads = this.size() > 0; |
174 this.node_.hidden = !hasDownloads; | 281 this.node_.hidden = !hasDownloads; |
175 noDownloadsOrResults.hidden = hasDownloads; | 282 noDownloadsOrResults.hidden = hasDownloads; |
176 | 283 |
177 if (loadTimeData.getBoolean('allow_deleting_history')) | 284 if (loadTimeData.getBoolean('allow_deleting_history')) |
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; | 285 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; |
| 286 |
| 287 this.rebuildFocusGrid_(); |
179 }; | 288 }; |
180 | 289 |
181 /** | 290 /** |
| 291 * Rebuild the focusGrid_ using the elements that each download will have. |
| 292 * @private |
| 293 */ |
| 294 Downloads.prototype.rebuildFocusGrid_ = function() { |
| 295 this.focusGrid_.destroy(); |
| 296 |
| 297 // Keys for downloads are in the reverse order of what is displayed. |
| 298 var keys = Object.keys(this.downloads_); |
| 299 for (var i = keys.length - 1; i >= 0; --i) { |
| 300 this.focusGrid_.addRow(new DownloadFocusRow(this.node_, |
| 301 this.downloads_[keys[i]])); |
| 302 } |
| 303 }; |
| 304 |
| 305 /** |
182 * Returns the number of downloads in the model. Used by tests. | 306 * Returns the number of downloads in the model. Used by tests. |
183 * @return {number} Returns the number of downloads shown on the page. | 307 * @return {number} Returns the number of downloads shown on the page. |
184 */ | 308 */ |
185 Downloads.prototype.size = function() { | 309 Downloads.prototype.size = function() { |
186 return Object.keys(this.downloads_).length; | 310 return Object.keys(this.downloads_).length; |
187 }; | 311 }; |
188 | 312 |
189 /** | 313 /** |
190 * Called whenever the downloads lists items have changed (either by being | 314 * Called whenever the downloads lists items have changed (either by being |
191 * updated, added, or removed). | 315 * updated, added, or removed). |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
978 if (Date.now() - start > 50) { | 1102 if (Date.now() - start > 50) { |
979 clearTimeout(resultsTimeout); | 1103 clearTimeout(resultsTimeout); |
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); | 1104 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); |
981 break; | 1105 break; |
982 } | 1106 } |
983 } | 1107 } |
984 } | 1108 } |
985 | 1109 |
986 // Add handlers to HTML elements. | 1110 // Add handlers to HTML elements. |
987 window.addEventListener('DOMContentLoaded', load); | 1111 window.addEventListener('DOMContentLoaded', load); |
OLD | NEW |