1 // Copyright 2015 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.
5 cr
.define('downloads', function() {
10 * @param {!downloads.ThrottledIconLoader} iconLoader
11 * @param {!downloads.ActionService} actionService
13 factoryImpl: function(iconLoader
, actionService
) {
14 /** @private {!downloads.ThrottledIconLoader} */
15 this.iconLoader_
= iconLoader
;
17 /** @private {!downloads.ActionService} */
18 this.actionService_
= actionService
;
23 reflectToAttribute
: true,
31 return new Promise(function(resolve
, reject
) {
32 this.resolveReadyPromise_
= resolve
;
38 observer
: 'onScrollbarWidthChange_',
44 computed
: 'computeCompletelyOnDisk_(' +
45 'data_.state, data_.file_externally_removed)',
55 cancel
: loadTimeData
.getString('controlCancel'),
56 discard
: loadTimeData
.getString('dangerDiscard'),
57 pause
: loadTimeData
.getString('controlPause'),
58 remove
: loadTimeData
.getString('controlRemoveFromList'),
59 resume
: loadTimeData
.getString('controlResume'),
60 restore
: loadTimeData
.getString('dangerRestore'),
61 retry
: loadTimeData
.getString('controlRetry'),
62 save
: loadTimeData
.getString('dangerSave'),
63 show
: loadTimeData
.getString('controlShowInFolder'),
69 computed
: 'computeIsDangerous_(data_.state)',
75 computed
: 'computeIsInProgress_(data_.state)',
81 computed
: 'computeShowCancel_(data_.state)',
87 computed
: 'computeShowProgress_(showCancel_, data_.percent)',
93 computed
: 'computeIsMalware_(isDangerous_, data_.danger_type)',
98 // TODO(dbeam): move all properties to |data_|.
101 value: function() { return {}; },
106 this.content
= this.$.content
;
107 this.resolveReadyPromise_();
110 /** @param {!downloads.Data} data */
111 update: function(data
) {
112 assert(!('id' in this.data_
) || this.data_
.id
== data
.id
);
115 data
.by_ext_id
=== this.data_
.by_ext_id
&&
116 data
.by_ext_name
=== this.data_
.by_ext_name
&&
117 data
.danger_type
=== this.data_
.danger_type
&&
118 data
.date_string
== this.data_
.date_string
&&
119 data
.file_externally_removed
== this.data_
.file_externally_removed
&&
120 data
.file_name
== this.data_
.file_name
&&
121 data
.file_path
== this.data_
.file_path
&&
122 data
.file_url
== this.data_
.file_url
&&
123 data
.last_reason_text
=== this.data_
.last_reason_text
&&
124 data
.otr
== this.data_
.otr
&&
125 data
.percent
=== this.data_
.percent
&&
126 data
.progress_status_text
=== this.data_
.progress_status_text
&&
127 data
.received
=== this.data_
.received
&&
128 data
.resume
== this.data_
.resume
&&
129 data
.retry
== this.data_
.retry
&&
130 data
.since_string
== this.data_
.since_string
&&
131 data
.started
== this.data_
.started
&&
132 data
.state
== this.data_
.state
&&
133 data
.total
== this.data_
.total
&&
134 data
.url
== this.data_
.url
) {
135 // TODO(dbeam): remove this once data binding is fully in place.
139 for (var key
in data
) {
140 this.set('data_.' + key
, data
[key
]);
143 /** @const */ var isActive
=
144 data
.state
!= downloads
.States
.CANCELLED
&&
145 data
.state
!= downloads
.States
.INTERRUPTED
&&
146 !data
.file_externally_removed
;
147 this.$.content
.classList
.toggle('is-active', isActive
);
148 this.$.content
.elevation
= isActive
? 1 : 0;
150 // Danger-dependent UI and controls.
151 this.$.content
.classList
.toggle('dangerous', this.isDangerous_
);
153 var description
= this.getDangerText_(data
) || this.getStatusText_(data
);
155 // Status goes in the "tag" (next to the file name) if there's no file.
156 this.ensureTextIs_(this.$.description
, isActive
? description
: '');
157 this.ensureTextIs_(this.$.tag
, isActive
? '' : description
);
159 this.$.content
.classList
.toggle('show-progress', this.showProgress_
);
163 if (this.isDangerous_
) {
166 this.$['file-link'].href
= data
.url
;
167 this.ensureTextIs_(this.$['file-link'], data
.file_name
);
169 this.$['file-link'].hidden
= !this.completelyOnDisk_
;
170 this.$.name
.hidden
= this.completelyOnDisk_
;
172 hideRemove
= this.showCancel_
||
173 !loadTimeData
.getBoolean('allowDeletingHistory');
175 /** @const */ var controlledByExtension
= data
.by_ext_id
&&
177 this.$['controlled-by'].hidden
= !controlledByExtension
;
178 if (controlledByExtension
) {
179 var link
= this.$['controlled-by'].querySelector('a');
180 link
.href
= 'chrome://extensions#' + data
.by_ext_id
;
181 link
.textContent
= data
.by_ext_name
;
184 var icon
= 'chrome://fileicon/' + encodeURIComponent(data
.file_path
);
185 this.iconLoader_
.loadScaledIcon(this.$['file-icon'], icon
);
188 this.$.remove
.style
.visibility
= hideRemove
? 'hidden' : '';
192 computeCompletelyOnDisk_: function() {
193 return this.data_
.state
== downloads
.States
.COMPLETE
&&
194 !this.data_
.file_externally_removed
;
198 computeDate_: function() {
199 assert(!this.hideDate
);
200 return assert(this.data_
.since_string
|| this.data_
.date_string
);
204 computeIsInProgress_: function() {
205 return this.data_
.state
== downloads
.States
.IN_PROGRESS
;
209 computeIsMalware_: function() {
210 return this.isDangerous_
&&
211 (this.data_
.danger_type
== downloads
.DangerType
.DANGEROUS_CONTENT
||
212 this.data_
.danger_type
== downloads
.DangerType
.DANGEROUS_HOST
||
213 this.data_
.danger_type
== downloads
.DangerType
.DANGEROUS_URL
||
214 this.data_
.danger_type
== downloads
.DangerType
.POTENTIALLY_UNWANTED
);
218 computeIsDangerous_: function() {
219 return this.data_
.state
== downloads
.States
.DANGEROUS
;
223 computeShowCancel_: function() {
224 return this.data_
.state
== downloads
.States
.IN_PROGRESS
||
225 this.data_
.state
== downloads
.States
.PAUSED
;
229 computeShowProgress_: function() {
230 return this.showCancel_
&& isFinite(this.data_
.percent
);
234 * Overwrite |el|'s textContent if it differs from |text|. This is done
235 * generally so quickly updating text can be copied via text selection.
236 * @param {!Element} el
237 * @param {string} text
240 ensureTextIs_: function(el
, text
) {
241 if (el
.textContent
!= text
)
242 el
.textContent
= text
;
246 * @param {!downloads.Data} data
247 * @return {string} Text describing the danger of a download. Empty if not
250 getDangerText_: function(data
) {
251 switch (data
.danger_type
) {
252 case downloads
.DangerType
.DANGEROUS_FILE
:
253 return loadTimeData
.getStringF('dangerFileDesc', data
.file_name
);
254 case downloads
.DangerType
.DANGEROUS_URL
:
255 return loadTimeData
.getString('dangerUrlDesc');
256 case downloads
.DangerType
.DANGEROUS_CONTENT
: // Fall through.
257 case downloads
.DangerType
.DANGEROUS_HOST
:
258 return loadTimeData
.getStringF('dangerContentDesc', data
.file_name
);
259 case downloads
.DangerType
.UNCOMMON_CONTENT
:
260 return loadTimeData
.getStringF('dangerUncommonDesc', data
.file_name
);
261 case downloads
.DangerType
.POTENTIALLY_UNWANTED
:
262 return loadTimeData
.getStringF('dangerSettingsDesc', data
.file_name
);
269 * @param {!downloads.Data} data
270 * @return {string} User-visible status update text.
273 getStatusText_: function(data
) {
274 switch (data
.state
) {
275 case downloads
.States
.IN_PROGRESS
:
276 case downloads
.States
.PAUSED
: // Fallthrough.
277 assert(typeof data
.progress_status_text
== 'string');
278 return data
.progress_status_text
;
279 case downloads
.States
.CANCELLED
:
280 return loadTimeData
.getString('statusCancelled');
281 case downloads
.States
.DANGEROUS
:
282 break; // Intentionally hit assertNotReached(); at bottom.
283 case downloads
.States
.INTERRUPTED
:
284 assert(typeof data
.last_reason_text
== 'string');
285 return data
.last_reason_text
;
286 case downloads
.States
.COMPLETE
:
287 return data
.file_externally_removed
?
288 loadTimeData
.getString('statusRemoved') : '';
295 isIndeterminate_: function() {
296 assert(this.showProgress_
);
297 return this.data_
.percent
== -1;
301 onCancelClick_: function() {
302 this.actionService_
.cancel(this.data_
.id
);
309 onDragStart_: function(e
) {
311 this.actionService_
.drag(this.data_
.id
);
318 onFileLinkClick_: function(e
) {
320 this.actionService_
.openFile(this.data_
.id
);
324 onPauseClick_: function() {
325 this.actionService_
.pause(this.data_
.id
);
329 onRemoveClick_: function() {
330 assert(!this.$.remove
.disabled
);
331 this.actionService_
.remove(this.data_
.id
);
335 onSaveDangerous_: function() {
336 this.actionService_
.saveDangerous(this.data_
.id
);
340 onDiscardDangerous_: function() {
341 this.actionService_
.discardDangerous(this.data_
.id
);
345 onResumeClick_: function() {
346 this.actionService_
.resume(this.data_
.id
);
350 onRetryClick_: function() {
351 this.actionService_
.download(this.$['file-link'].href
);
355 onScrollbarWidthChange_: function() {
359 var endCap
= this.$['end-cap'];
360 endCap
.style
.flexBasis
= '';
362 if (this.scrollbarWidth
) {
363 var basis
= parseInt(getComputedStyle(endCap
).flexBasis
, 10);
364 endCap
.style
.flexBasis
= basis
- this.scrollbarWidth
+ 'px';
369 onShowClick_: function() {
370 this.actionService_
.show(this.data_
.id
);