1 // Copyright 2013 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.
8 * Progress center panel.
10 * @param {HTMLElement} element DOM Element of the process center panel.
11 * @param {function(string)} cancelCallback Callback to becalled with the ID of
12 * the progress item when the cancel button is clicked.
15 var ProgressCenterPanel = function(element, cancelCallback) {
16 this.element_ = element;
17 this.openView_ = this.element_.querySelector('#progress-center-open-view');
18 this.closeView_ = this.element_.querySelector('#progress-center-close-view');
19 this.cancelCallback_ = cancelCallback;
22 * Reset is requested but it is pending until the transition of progress bar
27 this.resetRequested_ = false;
30 * Only progress item in the close view.
31 * @type {!HTMLElement}
34 this.closeViewItem_ = this.closeView_.querySelector('li');
38 // Register event handlers.
39 element.addEventListener('click', this.onClick_.bind(this));
40 element.addEventListener(
41 'webkitTransitionEnd', this.onItemTransitionEnd_.bind(this));
45 * Whether to use the new progress center UI or not.
46 * TODO(hirono): Remove the flag after replacing the old butter bar with the new
51 ProgressCenterPanel.ENABLED_ = true;
54 * Updates attributes of the item element.
55 * @param {!HTMLElement} element Element to be updated.
56 * @param {!ProgressCenterItem} item Progress center item.
59 ProgressCenterPanel.updateItemElement_ = function(element, item) {
60 // Sets element attributes.
61 element.setAttribute('data-progress-id', item.id);
62 element.setAttribute('data-progress-max', item.progressMax);
63 element.setAttribute('data-progress-value', item.progressValue);
64 element.className = '';
65 if (item.state === ProgressItemState.ERROR)
66 element.classList.add('error');
68 element.classList.add('cancelable');
70 // If the transition animation is needed, apply it.
71 var previousWidthRate =
72 parseInt(element.querySelector('.progress-track').style.width);
73 if (item.state === ProgressItemState.COMPLETE &&
74 previousWidthRate !== item.progressRateByPercent) {
75 // The attribute pre-complete means that the actual operation is already
76 // done but the UI transition of progress bar is not complete.
77 element.setAttribute('pre-complete', '');
79 element.querySelector('label').textContent = item.message;
82 // To commit the property change and to trigger the transition even if the
83 // change is done synchronously, assign the width value asynchronously.
84 setTimeout(function() {
85 var track = element.querySelector('.progress-track');
86 // When the progress rate is reverted, we does not use the transition
87 // animation. Specifying '0' overrides the CSS settings and specifying null
89 track.style.transitionDuration =
90 previousWidthRate > item.progressRateByPercent ? '0' : null;
91 track.style.width = item.progressRateByPercent + '%';
96 * Updates an item to the progress center panel.
97 * @param {!ProgressCenterItem} item Item including new contents.
98 * @param {!ProgressCenterItem} summarizedItem Item to be desplayed in the close
101 ProgressCenterPanel.prototype.updateItem = function(item, summarizedItem) {
102 // If reset is requested, force to reset.
103 if (this.resetRequested_)
107 var itemElement = this.getItemElement_(item.id);
110 // Check whether the item should be displayed or not by referring its state.
111 switch (item.state) {
112 // Should show the item.
113 case ProgressItemState.PROGRESSING:
114 case ProgressItemState.ERROR:
115 // If the item has not been added yet, create a new element and add it.
117 itemElement = this.createNewItemElement_();
118 this.openView_.insertBefore(itemElement, this.openView_.firstNode);
121 // Update the element by referring the item model.
122 ProgressCenterPanel.updateItemElement_(itemElement, item);
123 this.element_.hidden = false;
126 // Should not show the item.
127 case ProgressItemState.COMPLETE:
128 case ProgressItemState.CANCELED:
129 // If itemElement is not shown, just break.
133 // If the item is complete state, once update it because it may turn to
134 // have the pre-complete attribute.
135 if (item.state == ProgressItemState.COMPLETE)
136 ProgressCenterPanel.updateItemElement_(itemElement, item);
138 // If the item has the pre-complete attribute, keep showing it. Otherwise,
140 if (item.state !== ProgressItemState.COMPLETE ||
141 !itemElement.hasAttribute('pre-complete')) {
142 this.openView_.removeChild(itemElement);
147 // Update close view.
148 this.closeView_.classList.toggle('single', !summarizedItem.summarized);
149 ProgressCenterPanel.updateItemElement_(this.closeViewItem_, summarizedItem);
153 * Remove all the items.
154 * @param {boolean=} opt_force True if we force to reset and do not wait the
155 * transition of progress bar. False otherwise. False is default.
157 ProgressCenterPanel.prototype.reset = function(opt_force) {
158 if (!opt_force && this.element_.querySelector('[pre-complete]')) {
159 this.resetRequested_ = true;
164 this.resetRequested_ = false;
166 // Clear the all compete item.
167 this.openView_.innerHTML = '';
169 // Hide the progress center.
170 this.element_.hidden = true;
171 this.element_.classList.remove('opened');
175 * Gets an item element having the specified ID.
176 * @param {string} id progress item ID.
177 * @return {HTMLElement} Item element having the ID.
180 ProgressCenterPanel.prototype.getItemElement_ = function(id) {
181 var query = 'li[data-progress-id="' + id + '"]';
182 return this.openView_.querySelector(query);
186 * Creates an item element.
187 * @return {HTMLElement} Created item element.
190 ProgressCenterPanel.prototype.createNewItemElement_ = function() {
191 var label = this.element_.ownerDocument.createElement('label');
192 label.className = 'label';
194 var progressBarIndicator = this.element_.ownerDocument.createElement('div');
195 progressBarIndicator.className = 'progress-track';
197 var progressBar = this.element_.ownerDocument.createElement('div');
198 progressBar.className = 'progress-bar';
199 progressBar.appendChild(progressBarIndicator);
201 var cancelButton = this.element_.ownerDocument.createElement('button');
202 cancelButton.className = 'cancel';
203 cancelButton.setAttribute('tabindex', '-1');
205 var progressFrame = this.element_.ownerDocument.createElement('div');
206 progressFrame.className = 'progress-frame';
207 progressFrame.appendChild(progressBar);
208 progressFrame.appendChild(cancelButton);
210 var itemElement = this.element_.ownerDocument.createElement('li');
211 itemElement.appendChild(label);
212 itemElement.appendChild(progressFrame);
218 * Handles the transition end event of items.
219 * @param {Event} event Transition end event.
222 ProgressCenterPanel.prototype.onItemTransitionEnd_ = function(event) {
223 var itemElement = event.target.parentNode.parentNode.parentNode;
224 if (!itemElement.hasAttribute('pre-complete') ||
225 event.propertyName !== 'width')
227 if (itemElement !== this.closeViewItem_)
228 this.openView_.removeChild(itemElement);
230 itemElement.removeAttribute('pre-complete');
231 if (this.resetRequested_)
236 * Handles the click event.
237 * @param {Event} event Click event.
240 ProgressCenterPanel.prototype.onClick_ = function(event) {
241 if (event.target.classList.contains('toggle') &&
242 !this.closeView_.classList.contains('single'))
243 this.element_.classList.toggle('opened');
244 else if ((event.target.classList.contains('toggle') &&
245 this.closeView_.classList.contains('single')) ||
246 event.target.classList.contains('cancel'))
247 this.cancelCallback_(
248 event.target.parentNode.parentNode.getAttribute('data-progress-id'));