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 /** | 5 /** |
6 * The minimum about of time to display the butter bar for, in ms. | 6 * The minimum about of time to display the butter bar for, in ms. |
7 * Justification is 1000ms for minimum display time plus 300ms for transition | 7 * Justification is 1000ms for minimum display time plus 300ms for transition |
8 * duration. | 8 * duration. |
9 */ | 9 */ |
10 var MINIMUM_BUTTER_DISPLAY_TIME_MS = 1300; | 10 var MINIMUM_BUTTER_DISPLAY_TIME_MS = 1300; |
11 | 11 |
12 /** | 12 /** |
13 * Butter bar is shown on top of the file list and is used to show the copy | 13 * Butter bar is shown on top of the file list and is used to show the copy |
14 * progress and other messages. | 14 * progress and other messages. |
15 * @constructor | 15 * @constructor |
16 * @param {HTMLElement} dialogDom FileManager top-level div. | 16 * @param {HTMLElement} dialogDom FileManager top-level div. |
17 * @param {FileCopyManagerWrapper} copyManager The copy manager. | 17 * @param {FileCopyManagerWrapper} copyManager The copy manager. |
18 */ | 18 */ |
19 function ButterBar(dialogDom, copyManager) { | 19 function ButterBar(dialogDom, copyManager) { |
20 this.dialogDom_ = dialogDom; | 20 this.dialogDom_ = dialogDom; |
21 this.butter_ = this.dialogDom_.querySelector('#butter-bar'); | 21 this.butter_ = this.dialogDom_.querySelector('#butter-bar'); |
22 this.document_ = this.butter_.ownerDocument; | 22 this.document_ = this.butter_.ownerDocument; |
23 this.copyManager_ = copyManager; | 23 this.copyManager_ = copyManager; |
24 this.hideTimeout_ = null; | 24 this.hideTimeout_ = null; |
25 this.showTimeout_ = null; | 25 this.showTimeout_ = null; |
26 this.visible_ = false; | |
27 this.lastShowTime_ = 0; | 26 this.lastShowTime_ = 0; |
28 this.isError_ = false; | |
29 | 27 |
30 this.copyManager_.addEventListener('copy-progress', | 28 this.copyManager_.addEventListener('copy-progress', |
31 this.onCopyProgress_.bind(this)); | 29 this.onCopyProgress_.bind(this)); |
32 } | 30 } |
33 | 31 |
34 /** | 32 /** |
33 * @return {boolean} True if visible. | |
34 * @private | |
35 */ | |
36 ButterBar.prototype.isVisible_ = function() { | |
37 return this.butter_.classList.contains('visible'); | |
38 }; | |
39 | |
40 /** | |
41 * @return {boolean} True if displaying an error. | |
42 * @private | |
43 */ | |
44 ButterBar.prototype.isError_ = function() { | |
45 return this.butter_.classList.contains('error'); | |
46 }; | |
47 | |
48 /** | |
35 * Show butter bar. | 49 * Show butter bar. |
36 * @param {string} message The message to be shown. | 50 * @param {string} message The message to be shown. |
37 * @param {object} opt_options Options: 'actions', 'progress', 'timeout'. | 51 * @param {object} opt_options Options: 'actions', 'progress', 'timeout'. |
38 */ | 52 */ |
39 ButterBar.prototype.show = function(message, opt_options) { | 53 ButterBar.prototype.show = function(message, opt_options) { |
40 if (opt_options) { | 54 if (this.hideTimeout_) { |
Oleg Eterevsky
2012/08/03 07:36:13
These 4 lines appear at least 3 times. Maybe extra
Vladislav Kaznacheev
2012/08/03 08:20:04
Done.
| |
41 if ('actions' in opt_options) { | 55 clearTimeout(this.hideTimeout_); |
42 var actions = this.butter_.querySelector('.actions'); | 56 this.hideTimeout_ = null; |
43 while (actions.childNodes.length) | 57 } |
44 actions.removeChild(actions.firstChild); | 58 if (this.showTimeout_) { |
45 for (var label in opt_options.actions) { | 59 clearTimeout(this.showTimeout_); |
46 var link = this.document_.createElement('a'); | 60 this.showTimeout_ = null; |
47 link.addEventListener('click', function() { | |
48 opt_options.actions[label](); | |
49 return false; | |
50 }); | |
51 actions.appendChild(link); | |
52 } | |
53 actions.classList.remove('hide-in-butter'); | |
54 } | |
55 if ('progress' in opt_options) { | |
56 this.butter_.querySelector('.progress-bar').classList.remove( | |
57 'hide-in-butter'); | |
58 } | |
59 } | 61 } |
60 | 62 |
61 this.visible_ = true; | 63 var actions = this.butter_.querySelector('.actions'); |
62 this.isError_ = false; | 64 actions.textContent = ''; |
65 if (opt_options && 'actions' in opt_options) { | |
66 for (var label in opt_options.actions) { | |
67 var link = this.document_.createElement('a'); | |
68 link.addEventListener('click', function(callback) { | |
Oleg Eterevsky
2012/08/03 07:36:13
Why did you change the way this function is writte
Vladislav Kaznacheev
2012/08/03 08:20:04
A closure inside a loop is bound to the last value
| |
69 callback(); | |
70 return false; | |
71 }.bind(null, opt_options.actions[label])); | |
72 actions.appendChild(link); | |
73 } | |
74 actions.hidden = false; | |
75 } else | |
76 actions.hidden = true; | |
Oleg Eterevsky
2012/08/03 07:36:13
Could you please add braces here? Otherwise it loo
Vladislav Kaznacheev
2012/08/03 08:20:04
Done.
| |
77 | |
78 this.butter_.querySelector('.progress-bar').hidden = | |
79 !(opt_options && 'progress' in opt_options); | |
80 | |
81 this.butter_.classList.remove('error'); | |
82 this.butter_.classList.remove('visible'); // Will be shown in update_ | |
63 this.update_(message, opt_options); | 83 this.update_(message, opt_options); |
64 this.lastShowTime_ = Date.now(); | |
65 }; | 84 }; |
66 | 85 |
67 /** | 86 /** |
68 * Show error message in butter bar. | 87 * Show error message in butter bar. |
69 * @private | 88 * @private |
70 * @param {string} message Message. | 89 * @param {string} message Message. |
71 * @param {object} opt_options Same as in show(). | 90 * @param {object} opt_options Same as in show(). |
72 */ | 91 */ |
73 ButterBar.prototype.showError_ = function(message, opt_options) { | 92 ButterBar.prototype.showError_ = function(message, opt_options) { |
74 this.show(message, opt_options); | 93 this.show(message, opt_options); |
75 this.isError_ = true; | |
76 this.butter_.classList.add('error'); | 94 this.butter_.classList.add('error'); |
77 }; | 95 }; |
78 | 96 |
79 /** | 97 /** |
80 * Set message and/or progress. | 98 * Set message and/or progress. |
81 * @private | 99 * @private |
82 * @param {string} message Message. | 100 * @param {string} message Message. |
83 * @param {object} opt_options Same as in show(). | 101 * @param {object} opt_options Same as in show(). |
84 */ | 102 */ |
85 ButterBar.prototype.update_ = function(message, opt_options) { | 103 ButterBar.prototype.update_ = function(message, opt_options) { |
86 if (!opt_options) | 104 if (!opt_options) |
87 opt_options = {}; | 105 opt_options = {}; |
88 | 106 |
89 var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000; | 107 var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000; |
Oleg Eterevsky
2012/08/03 07:36:13
Could you please swap this line and the next if, s
Vladislav Kaznacheev
2012/08/03 08:20:04
Done.
| |
90 | 108 |
91 if (this.hideTimeout_) | 109 if (this.hideTimeout_) { |
92 clearTimeout(this.hideTimeout_); | 110 clearTimeout(this.hideTimeout_); |
111 this.hideTimeout_ = null; | |
112 } | |
93 | 113 |
94 if (timeout) { | 114 if (timeout) { |
95 this.hideTimeout_ = setTimeout(function() { | 115 this.hideTimeout_ = setTimeout(function() { |
96 this.hideButter(); | 116 this.hideTimeout_ = null; |
97 this.hideTimeout_ = null; | 117 this.hide_(); |
Oleg Eterevsky
2012/08/03 07:36:13
I missed this while refactoring. Thanks!
| |
98 }.bind(this), timeout); | 118 }.bind(this), timeout); |
99 } | 119 } |
100 | 120 |
101 this.butter_.querySelector('.butter-message').textContent = message; | 121 this.butter_.querySelector('.butter-message').textContent = message; |
102 if (message) { | 122 if (message && !this.isVisible_()) { |
103 // The butter bar is made visible on the first non-empty message. | 123 // The butter bar is made visible on the first non-empty message. |
104 this.butter_.classList.remove('before-show'); | 124 this.butter_.classList.add('visible'); |
125 this.lastShowTime_ = Date.now(); | |
105 } | 126 } |
106 if (opt_options && 'progress' in opt_options) { | 127 if (opt_options && 'progress' in opt_options) { |
107 this.butter_.querySelector('.progress-track').style.width = | 128 this.butter_.querySelector('.progress-track').style.width = |
108 (opt_options.progress * 100) + '%'; | 129 (opt_options.progress * 100) + '%'; |
109 } | 130 } |
110 | 131 |
111 this.butter_.style.left = | 132 this.butter_.style.left = |
112 (this.dialogDom_.clientWidth - this.butter_.clientWidth) / 2 + 'px'; | 133 (this.dialogDom_.clientWidth - this.butter_.clientWidth) / 2 + 'px'; |
113 }; | 134 }; |
114 | 135 |
115 /** | 136 /** |
116 * Hide butter bar. There might be some delay before hiding so that butter bar | 137 * Hide butter bar. There might be some delay before hiding so that butter bar |
117 * would be shown for no less than the minimal time. | 138 * would be shown for no less than the minimal time. |
139 * @param {boolean} opt_force If true hide immediately. | |
118 * @private | 140 * @private |
119 */ | 141 */ |
120 ButterBar.prototype.hide_ = function() { | 142 ButterBar.prototype.hide_ = function(opt_force) { |
121 if (this.visible_) { | 143 if (this.hideTimeout_) { |
122 var delay = Math.max( | 144 clearTimeout(this.hideTimeout_); |
123 MINIMUM_BUTTER_DISPLAY_TIME_MS - (Date.now() - this.lastShowTime_), 0); | 145 this.hideTimeout_ = null; |
146 } | |
124 | 147 |
125 var butter = this.butter_; | 148 if (!this.isVisible_()) |
149 return; | |
126 | 150 |
127 function hideButter() { | 151 var delay = |
128 butter.classList.remove('error'); | 152 MINIMUM_BUTTER_DISPLAY_TIME_MS - (Date.now() - this.lastShowTime_); |
129 butter.classList.remove('after-show'); | |
130 butter.classList.add('before-show'); | |
131 butter.querySelector('.actions').classList.add('hide-in-butter'); | |
132 butter.querySelector('.progress-bar').classList.add('hide-in-butter'); | |
133 } | |
134 | 153 |
135 setTimeout(function() { butter.classList.add('after-show'); }, delay); | 154 if (opt_force || delay <= 0) { |
136 setTimeout(hideButter, delay + 1000); | 155 this.butter_.classList.remove('visible'); |
137 this.visible_ = false; | 156 } else { |
157 // Reschedule hide to comply with the minimal display time. | |
158 this.hideTimeout_ = setTimeout(function() { | |
159 this.hideTimeout_ = null; | |
160 this.hide_(true); | |
161 }.bind(this), delay); | |
138 } | 162 } |
139 }; | 163 }; |
140 | 164 |
141 /** | 165 /** |
142 * If butter bar shows an error message, close it. | 166 * If butter bar shows an error message, close it. |
143 * @return {boolean} True if butter bar was closed. | 167 * @return {boolean} True if butter bar was closed. |
144 */ | 168 */ |
145 ButterBar.prototype.hideError = function() { | 169 ButterBar.prototype.hideError = function() { |
146 if (this.visible_ && this.isError_) { | 170 if (this.isVisible_() && this.isError_()) { |
147 this.hide_(); | 171 this.hide_(true /* force */); |
148 clearTimeout(this.hideTimeout_); | |
149 return true; | 172 return true; |
150 } else { | 173 } else { |
151 return false; | 174 return false; |
152 } | 175 } |
153 }; | 176 }; |
154 | 177 |
155 /** | 178 /** |
156 * Init butter bar for showing copy progress. | 179 * Set up butter bar for showing copy progress. |
157 * @private | 180 * @private |
158 */ | 181 */ |
159 ButterBar.prototype.init_ = function() { | 182 ButterBar.prototype.showProgress_ = function() { |
160 var progress = this.copyManager_.getProgress(); | 183 var progress = this.copyManager_.getProgress(); |
161 var options = {progress: progress.percentage, actions: {}, timeout: 0}; | 184 var options = {progress: progress.percentage, actions: {}, timeout: 0}; |
162 options.actions[str('CANCEL_LABEL')] = | 185 options.actions[str('CANCEL_LABEL')] = |
163 this.copyManager_.requestCancel.bind(this.copyManager_); | 186 this.copyManager_.requestCancel.bind(this.copyManager_); |
164 this.show(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), options); | 187 this.show(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), options); |
165 }; | 188 }; |
166 | 189 |
167 /** | 190 /** |
168 * 'copy-progress' event handler. Show progress or an appropriate message. | 191 * 'copy-progress' event handler. Show progress or an appropriate message. |
169 * @private | 192 * @private |
170 * @param {cr.Event} event A 'copy-progress' event from FileCopyManager. | 193 * @param {cr.Event} event A 'copy-progress' event from FileCopyManager. |
171 */ | 194 */ |
172 ButterBar.prototype.onCopyProgress_ = function(event) { | 195 ButterBar.prototype.onCopyProgress_ = function(event) { |
173 var progress = this.copyManager_.getProgress(); | 196 var progress = this.copyManager_.getProgress(); |
174 | 197 |
198 if (this.showTimeout_ && event.reason != 'PROGRESS') { | |
199 clearTimeout(this.showTimeout_); | |
200 this.showTimeout_ = null; | |
201 } | |
202 | |
175 switch (event.reason) { | 203 switch (event.reason) { |
176 case 'BEGIN': | 204 case 'BEGIN': |
177 this.hide_(); | 205 this.showTimeout_ = setTimeout(function() { |
178 clearTimeout(this.timeout_); | 206 this.showTimeout_ = null; |
179 // If the copy process lasts more than 500 ms, we show a progress bar. | 207 this.showProgress_(); |
180 this.showTimeout_ = setTimeout(this.init_.bind(this), 500); | 208 }.bind(this), 500); |
181 break; | 209 break; |
182 | 210 |
183 case 'PROGRESS': | 211 case 'PROGRESS': |
184 if (this.visible_) { | 212 if (this.isVisible_()) { |
185 var options = {'progress': progress.percentage, timeout: 0}; | 213 var options = {'progress': progress.percentage, timeout: 0}; |
186 this.update_(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), | 214 this.update_(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), |
187 options); | 215 options); |
188 } | 216 } |
189 break; | 217 break; |
190 | 218 |
191 case 'SUCCESS': | 219 case 'SUCCESS': |
192 clearTimeout(this.showTimeout_); | |
193 this.hide_(); | 220 this.hide_(); |
194 break; | 221 break; |
195 | 222 |
196 case 'CANCELLED': | 223 case 'CANCELLED': |
197 this.show(str('PASTE_CANCELLED'), {timeout: 1000}); | 224 this.show(str('PASTE_CANCELLED'), {timeout: 1000}); |
198 break; | 225 break; |
199 | 226 |
200 case 'ERROR': | 227 case 'ERROR': |
201 clearTimeout(this.showTimeout_); | |
202 if (event.error.reason === 'TARGET_EXISTS') { | 228 if (event.error.reason === 'TARGET_EXISTS') { |
203 var name = event.error.data.name; | 229 var name = event.error.data.name; |
204 if (event.error.data.isDirectory) | 230 if (event.error.data.isDirectory) |
205 name += '/'; | 231 name += '/'; |
206 this.showError_(strf('PASTE_TARGET_EXISTS_ERROR', name)); | 232 this.showError_(strf('PASTE_TARGET_EXISTS_ERROR', name)); |
207 } else if (event.error.reason === 'FILESYSTEM_ERROR') { | 233 } else if (event.error.reason === 'FILESYSTEM_ERROR') { |
208 if (event.error.data.toGDrive && | 234 if (event.error.data.toGDrive && |
209 event.error.data.code === FileError.QUOTA_EXCEEDED_ERR) { | 235 event.error.data.code === FileError.QUOTA_EXCEEDED_ERR) { |
210 // The alert will be shown in FileManager.onCopyProgress_. | 236 // The alert will be shown in FileManager.onCopyProgress_. |
211 this.hide_(); | 237 this.hide_(); |
212 } else { | 238 } else { |
213 this.showError_(strf('PASTE_FILESYSTEM_ERROR', | 239 this.showError_(strf('PASTE_FILESYSTEM_ERROR', |
214 getFileErrorString(event.error.data.code))); | 240 getFileErrorString(event.error.data.code))); |
215 } | 241 } |
216 } else { | 242 } else { |
217 this.showError_(strf('PASTE_UNEXPECTED_ERROR', event.error)); | 243 this.showError_(strf('PASTE_UNEXPECTED_ERROR', event.error)); |
218 } | 244 } |
219 break; | 245 break; |
220 | 246 |
221 default: | 247 default: |
222 console.log('Unknown "copy-progress" event reason: ' + event.reason); | 248 console.log('Unknown "copy-progress" event reason: ' + event.reason); |
223 } | 249 } |
224 }; | 250 }; |
OLD | NEW |