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 this.clearShowTimeout_(); |
41 if ('actions' in opt_options) { | 55 this.clearHideTimeout_(); |
42 var actions = this.butter_.querySelector('.actions'); | 56 |
43 while (actions.childNodes.length) | 57 var actions = this.butter_.querySelector('.actions'); |
44 actions.removeChild(actions.firstChild); | 58 actions.textContent = ''; |
45 for (var label in opt_options.actions) { | 59 if (opt_options && 'actions' in opt_options) { |
46 var link = this.document_.createElement('a'); | 60 for (var label in opt_options.actions) { |
47 link.addEventListener('click', function() { | 61 var link = this.document_.createElement('a'); |
48 opt_options.actions[label](); | 62 link.addEventListener('click', function(callback) { |
49 return false; | 63 callback(); |
50 }); | 64 return false; |
51 actions.appendChild(link); | 65 }.bind(null, opt_options.actions[label])); |
52 } | 66 actions.appendChild(link); |
53 actions.classList.remove('hide-in-butter'); | |
54 } | 67 } |
55 if ('progress' in opt_options) { | 68 actions.hidden = false; |
56 this.butter_.querySelector('.progress-bar').classList.remove( | 69 } else { |
57 'hide-in-butter'); | 70 actions.hidden = true; |
58 } | |
59 } | 71 } |
60 | 72 |
61 this.visible_ = true; | 73 this.butter_.querySelector('.progress-bar').hidden = |
62 this.isError_ = false; | 74 !(opt_options && 'progress' in opt_options); |
| 75 |
| 76 this.butter_.classList.remove('error'); |
| 77 this.butter_.classList.remove('visible'); // Will be shown in update_ |
63 this.update_(message, opt_options); | 78 this.update_(message, opt_options); |
64 this.lastShowTime_ = Date.now(); | |
65 }; | 79 }; |
66 | 80 |
67 /** | 81 /** |
68 * Show error message in butter bar. | 82 * Show error message in butter bar. |
69 * @private | 83 * @private |
70 * @param {string} message Message. | 84 * @param {string} message Message. |
71 * @param {object} opt_options Same as in show(). | 85 * @param {object} opt_options Same as in show(). |
72 */ | 86 */ |
73 ButterBar.prototype.showError_ = function(message, opt_options) { | 87 ButterBar.prototype.showError_ = function(message, opt_options) { |
74 this.show(message, opt_options); | 88 this.show(message, opt_options); |
75 this.isError_ = true; | |
76 this.butter_.classList.add('error'); | 89 this.butter_.classList.add('error'); |
77 }; | 90 }; |
78 | 91 |
79 /** | 92 /** |
80 * Set message and/or progress. | 93 * Set message and/or progress. |
81 * @private | 94 * @private |
82 * @param {string} message Message. | 95 * @param {string} message Message. |
83 * @param {object} opt_options Same as in show(). | 96 * @param {object} opt_options Same as in show(). |
84 */ | 97 */ |
85 ButterBar.prototype.update_ = function(message, opt_options) { | 98 ButterBar.prototype.update_ = function(message, opt_options) { |
86 if (!opt_options) | 99 if (!opt_options) |
87 opt_options = {}; | 100 opt_options = {}; |
88 | 101 |
| 102 this.clearHideTimeout_(); |
| 103 |
89 var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000; | 104 var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000; |
90 | |
91 if (this.hideTimeout_) | |
92 clearTimeout(this.hideTimeout_); | |
93 | |
94 if (timeout) { | 105 if (timeout) { |
95 this.hideTimeout_ = setTimeout(function() { | 106 this.hideTimeout_ = setTimeout(function() { |
96 this.hideButter(); | 107 this.hideTimeout_ = null; |
97 this.hideTimeout_ = null; | 108 this.hide_(); |
98 }.bind(this), timeout); | 109 }.bind(this), timeout); |
99 } | 110 } |
100 | 111 |
101 this.butter_.querySelector('.butter-message').textContent = message; | 112 this.butter_.querySelector('.butter-message').textContent = message; |
102 if (message) { | 113 if (message && !this.isVisible_()) { |
103 // The butter bar is made visible on the first non-empty message. | 114 // The butter bar is made visible on the first non-empty message. |
104 this.butter_.classList.remove('before-show'); | 115 this.butter_.classList.add('visible'); |
| 116 this.lastShowTime_ = Date.now(); |
105 } | 117 } |
106 if (opt_options && 'progress' in opt_options) { | 118 if (opt_options && 'progress' in opt_options) { |
107 this.butter_.querySelector('.progress-track').style.width = | 119 this.butter_.querySelector('.progress-track').style.width = |
108 (opt_options.progress * 100) + '%'; | 120 (opt_options.progress * 100) + '%'; |
109 } | 121 } |
110 | 122 |
111 this.butter_.style.left = | 123 this.butter_.style.left = |
112 (this.dialogDom_.clientWidth - this.butter_.clientWidth) / 2 + 'px'; | 124 (this.dialogDom_.clientWidth - this.butter_.clientWidth) / 2 + 'px'; |
113 }; | 125 }; |
114 | 126 |
115 /** | 127 /** |
116 * Hide butter bar. There might be some delay before hiding so that butter bar | 128 * 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. | 129 * would be shown for no less than the minimal time. |
| 130 * @param {boolean} opt_force If true hide immediately. |
118 * @private | 131 * @private |
119 */ | 132 */ |
120 ButterBar.prototype.hide_ = function() { | 133 ButterBar.prototype.hide_ = function(opt_force) { |
121 if (this.visible_) { | 134 this.clearHideTimeout_(); |
122 var delay = Math.max( | |
123 MINIMUM_BUTTER_DISPLAY_TIME_MS - (Date.now() - this.lastShowTime_), 0); | |
124 | 135 |
125 var butter = this.butter_; | 136 if (!this.isVisible_()) |
| 137 return; |
126 | 138 |
127 function hideButter() { | 139 var delay = |
128 butter.classList.remove('error'); | 140 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 | 141 |
135 setTimeout(function() { butter.classList.add('after-show'); }, delay); | 142 if (opt_force || delay <= 0) { |
136 setTimeout(hideButter, delay + 1000); | 143 this.butter_.classList.remove('visible'); |
137 this.visible_ = false; | 144 } else { |
| 145 // Reschedule hide to comply with the minimal display time. |
| 146 this.hideTimeout_ = setTimeout(function() { |
| 147 this.hideTimeout_ = null; |
| 148 this.hide_(true); |
| 149 }.bind(this), delay); |
138 } | 150 } |
139 }; | 151 }; |
140 | 152 |
141 /** | 153 /** |
142 * If butter bar shows an error message, close it. | 154 * If butter bar shows an error message, close it. |
143 * @return {boolean} True if butter bar was closed. | 155 * @return {boolean} True if butter bar was closed. |
144 */ | 156 */ |
145 ButterBar.prototype.hideError = function() { | 157 ButterBar.prototype.hideError = function() { |
146 if (this.visible_ && this.isError_) { | 158 if (this.isVisible_() && this.isError_()) { |
147 this.hide_(); | 159 this.hide_(true /* force */); |
148 clearTimeout(this.hideTimeout_); | |
149 return true; | 160 return true; |
150 } else { | 161 } else { |
151 return false; | 162 return false; |
152 } | 163 } |
153 }; | 164 }; |
154 | 165 |
155 /** | 166 /** |
156 * Init butter bar for showing copy progress. | 167 * Clear the show timeout if it is set. |
157 * @private | 168 * @private |
158 */ | 169 */ |
159 ButterBar.prototype.init_ = function() { | 170 ButterBar.prototype.clearShowTimeout_ = function() { |
| 171 if (this.showTimeout_) { |
| 172 clearTimeout(this.hideTimeout_); |
| 173 this.showTimeout_ = null; |
| 174 } |
| 175 }; |
| 176 |
| 177 /** |
| 178 * Clear the hide timeout if it is set. |
| 179 * @private |
| 180 */ |
| 181 ButterBar.prototype.clearHideTimeout_ = function() { |
| 182 if (this.hideTimeout_) { |
| 183 clearTimeout(this.hideTimeout_); |
| 184 this.hideTimeout_ = null; |
| 185 } |
| 186 }; |
| 187 |
| 188 /** |
| 189 * Set up butter bar for showing copy progress. |
| 190 * @private |
| 191 */ |
| 192 ButterBar.prototype.showProgress_ = function() { |
160 var progress = this.copyManager_.getProgress(); | 193 var progress = this.copyManager_.getProgress(); |
161 var options = {progress: progress.percentage, actions: {}, timeout: 0}; | 194 var options = {progress: progress.percentage, actions: {}, timeout: 0}; |
162 options.actions[str('CANCEL_LABEL')] = | 195 options.actions[str('CANCEL_LABEL')] = |
163 this.copyManager_.requestCancel.bind(this.copyManager_); | 196 this.copyManager_.requestCancel.bind(this.copyManager_); |
164 this.show(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), options); | 197 this.show(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), options); |
165 }; | 198 }; |
166 | 199 |
167 /** | 200 /** |
168 * 'copy-progress' event handler. Show progress or an appropriate message. | 201 * 'copy-progress' event handler. Show progress or an appropriate message. |
169 * @private | 202 * @private |
170 * @param {cr.Event} event A 'copy-progress' event from FileCopyManager. | 203 * @param {cr.Event} event A 'copy-progress' event from FileCopyManager. |
171 */ | 204 */ |
172 ButterBar.prototype.onCopyProgress_ = function(event) { | 205 ButterBar.prototype.onCopyProgress_ = function(event) { |
173 var progress = this.copyManager_.getProgress(); | 206 var progress = this.copyManager_.getProgress(); |
174 | 207 |
| 208 if (event.reason != 'PROGRESS') |
| 209 this.clearShowTimeout_(); |
| 210 |
175 switch (event.reason) { | 211 switch (event.reason) { |
176 case 'BEGIN': | 212 case 'BEGIN': |
177 this.hide_(); | 213 this.showTimeout_ = setTimeout(function() { |
178 clearTimeout(this.timeout_); | 214 this.showTimeout_ = null; |
179 // If the copy process lasts more than 500 ms, we show a progress bar. | 215 this.showProgress_(); |
180 this.showTimeout_ = setTimeout(this.init_.bind(this), 500); | 216 }.bind(this), 500); |
181 break; | 217 break; |
182 | 218 |
183 case 'PROGRESS': | 219 case 'PROGRESS': |
184 if (this.visible_) { | 220 if (this.isVisible_()) { |
185 var options = {'progress': progress.percentage, timeout: 0}; | 221 var options = {'progress': progress.percentage, timeout: 0}; |
186 this.update_(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), | 222 this.update_(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), |
187 options); | 223 options); |
188 } | 224 } |
189 break; | 225 break; |
190 | 226 |
191 case 'SUCCESS': | 227 case 'SUCCESS': |
192 clearTimeout(this.showTimeout_); | |
193 this.hide_(); | 228 this.hide_(); |
194 break; | 229 break; |
195 | 230 |
196 case 'CANCELLED': | 231 case 'CANCELLED': |
197 this.show(str('PASTE_CANCELLED'), {timeout: 1000}); | 232 this.show(str('PASTE_CANCELLED'), {timeout: 1000}); |
198 break; | 233 break; |
199 | 234 |
200 case 'ERROR': | 235 case 'ERROR': |
201 clearTimeout(this.showTimeout_); | |
202 if (event.error.reason === 'TARGET_EXISTS') { | 236 if (event.error.reason === 'TARGET_EXISTS') { |
203 var name = event.error.data.name; | 237 var name = event.error.data.name; |
204 if (event.error.data.isDirectory) | 238 if (event.error.data.isDirectory) |
205 name += '/'; | 239 name += '/'; |
206 this.showError_(strf('PASTE_TARGET_EXISTS_ERROR', name)); | 240 this.showError_(strf('PASTE_TARGET_EXISTS_ERROR', name)); |
207 } else if (event.error.reason === 'FILESYSTEM_ERROR') { | 241 } else if (event.error.reason === 'FILESYSTEM_ERROR') { |
208 if (event.error.data.toGDrive && | 242 if (event.error.data.toGDrive && |
209 event.error.data.code === FileError.QUOTA_EXCEEDED_ERR) { | 243 event.error.data.code === FileError.QUOTA_EXCEEDED_ERR) { |
210 // The alert will be shown in FileManager.onCopyProgress_. | 244 // The alert will be shown in FileManager.onCopyProgress_. |
211 this.hide_(); | 245 this.hide_(); |
212 } else { | 246 } else { |
213 this.showError_(strf('PASTE_FILESYSTEM_ERROR', | 247 this.showError_(strf('PASTE_FILESYSTEM_ERROR', |
214 getFileErrorString(event.error.data.code))); | 248 getFileErrorString(event.error.data.code))); |
215 } | 249 } |
216 } else { | 250 } else { |
217 this.showError_(strf('PASTE_UNEXPECTED_ERROR', event.error)); | 251 this.showError_(strf('PASTE_UNEXPECTED_ERROR', event.error)); |
218 } | 252 } |
219 break; | 253 break; |
220 | 254 |
221 default: | 255 default: |
222 console.log('Unknown "copy-progress" event reason: ' + event.reason); | 256 console.log('Unknown "copy-progress" event reason: ' + event.reason); |
223 } | 257 } |
224 }; | 258 }; |
OLD | NEW |