| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| 'use strict'; |
| |
| /** |
| * Progress center panel. |
| * |
| * @param {HTMLElement} element DOM Element of the process center panel. |
| * @constructor |
| */ |
| var ProgressCenterPanel = function(element) { |
| this.element_ = element; |
| this.openView_ = this.element_.querySelector('#progress-center-open-view'); |
| this.closeView_ = this.element_.querySelector('#progress-center-close-view'); |
| |
| /** |
| * Reset is requested but it is pending until the transition of progress bar |
| * is complete. |
| * @type {boolean} |
| * @private |
| */ |
| this.resetRequested_ = false; |
| |
| /** |
| * Only progress item in the close view. |
| * @type {!HTMLElement} |
| * @private |
| */ |
| this.closeViewItem_ = this.closeView_.querySelector('li'); |
| |
| /** |
| * Callback to becalled with the ID of the progress item when the cancel |
| * button is clicked. |
| */ |
| this.cancelCallback = null; |
| |
| Object.seal(this); |
| |
| // Register event handlers. |
| element.addEventListener('click', this.onClick_.bind(this)); |
| element.addEventListener( |
| 'webkitTransitionEnd', this.onItemTransitionEnd_.bind(this)); |
| }; |
| |
| /** |
| * Updates attributes of the item element. |
| * @param {!HTMLElement} element Element to be updated. |
| * @param {!ProgressCenterItem} item Progress center item. |
| * @private |
| */ |
| ProgressCenterPanel.updateItemElement_ = function(element, item) { |
| // Sets element attributes. |
| element.setAttribute('data-progress-id', item.id); |
| element.setAttribute('data-progress-max', item.progressMax); |
| element.setAttribute('data-progress-value', item.progressValue); |
| element.className = ''; |
| if (item.state === ProgressItemState.ERROR) |
| element.classList.add('error'); |
| if (item.cancelable) |
| element.classList.add('cancelable'); |
| |
| // Only when the previousWidthRate is not NaN (when style width is already |
| // set) and the progress rate increases, we use transition animation. |
| var previousWidthRate = |
| parseInt(element.querySelector('.progress-track').style.width); |
| var animation = !isNaN(previousWidthRate) && |
| previousWidthRate < item.progressRateInPercent; |
| if (item.state === ProgressItemState.COMPLETED && animation) { |
| // The attribute pre-complete means that the actual operation is already |
| // done but the UI transition of progress bar is not complete. |
| element.setAttribute('pre-complete', ''); |
| } else { |
| element.querySelector('label').textContent = item.message; |
| } |
| |
| // To commit the property change and to trigger the transition even if the |
| // change is done synchronously, assign the width value asynchronously. |
| setTimeout(function() { |
| var track = element.querySelector('.progress-track'); |
| track.classList.toggle('animated', animation); |
| track.style.width = item.progressRateInPercent + '%'; |
| track.hidden = false; |
| }, 0); |
| }; |
| |
| /** |
| * Updates an item to the progress center panel. |
| * @param {!ProgressCenterItem} item Item including new contents. |
| */ |
| ProgressCenterPanel.prototype.updateItem = function(item) { |
| // If reset is requested, force to reset. |
| if (this.resetRequested_) |
| this.reset(true); |
| |
| // Update the item. |
| var itemElement = this.getItemElement_(item.id); |
| var removed = false; |
| |
| // Check whether the item should be displayed or not by referring its state. |
| switch (item.state) { |
| // Should show the item. |
| case ProgressItemState.PROGRESSING: |
| case ProgressItemState.ERROR: |
| // If the item has not been added yet, create a new element and add it. |
| if (!itemElement) { |
| itemElement = this.createNewItemElement_(); |
| this.openView_.insertBefore(itemElement, this.openView_.firstNode); |
| } |
| |
| // Update the element by referring the item model. |
| ProgressCenterPanel.updateItemElement_(itemElement, item); |
| this.element_.hidden = false; |
| break; |
| |
| // Should not show the item. |
| case ProgressItemState.COMPLETED: |
| case ProgressItemState.CANCELED: |
| // If itemElement is not shown, just break. |
| if (!itemElement) |
| break; |
| |
| // If the item is complete state, once update it because it may turn to |
| // have the pre-complete attribute. |
| if (item.state === ProgressItemState.COMPLETED) |
| ProgressCenterPanel.updateItemElement_(itemElement, item); |
| |
| // If the item has the pre-complete attribute, keep showing it. Otherwise, |
| // just remove it. |
| if (item.state !== ProgressItemState.COMPLETED || |
| !itemElement.hasAttribute('pre-complete')) { |
| this.openView_.removeChild(itemElement); |
| } |
| break; |
| } |
| }; |
| |
| /** |
| * Updates close showing summarized item. |
| * @param {!ProgressCenterItem} summarizedItem Item to be displayed in the close |
| * view. |
| */ |
| ProgressCenterPanel.prototype.updateCloseView = function(summarizedItem) { |
| this.closeView_.classList.toggle('single', !summarizedItem.summarized); |
| ProgressCenterPanel.updateItemElement_(this.closeViewItem_, summarizedItem); |
| }; |
| |
| /** |
| * Remove all the items. |
| * @param {boolean=} opt_force True if we force to reset and do not wait the |
| * transition of progress bar. False otherwise. False is default. |
| */ |
| ProgressCenterPanel.prototype.reset = function(opt_force) { |
| if (!opt_force && this.element_.querySelector('[pre-complete]')) { |
| this.resetRequested_ = true; |
| return; |
| } |
| |
| // Clear the flag. |
| this.resetRequested_ = false; |
| |
| // Clear the all compete item. |
| this.openView_.innerHTML = ''; |
| |
| // Clear track width of close view. |
| this.closeViewItem_.querySelector('.progress-track').style.width = ''; |
| |
| // Hide the progress center. |
| this.element_.hidden = true; |
| this.closeViewItem_.querySelector('.progress-track').hidden = true; |
| this.element_.classList.remove('opened'); |
| }; |
| |
| /** |
| * Gets an item element having the specified ID. |
| * @param {string} id progress item ID. |
| * @return {HTMLElement} Item element having the ID. |
| * @private |
| */ |
| ProgressCenterPanel.prototype.getItemElement_ = function(id) { |
| var query = 'li[data-progress-id="' + id + '"]'; |
| return this.openView_.querySelector(query); |
| }; |
| |
| /** |
| * Creates an item element. |
| * @return {HTMLElement} Created item element. |
| * @private |
| */ |
| ProgressCenterPanel.prototype.createNewItemElement_ = function() { |
| var label = this.element_.ownerDocument.createElement('label'); |
| label.className = 'label'; |
| |
| var progressBarIndicator = this.element_.ownerDocument.createElement('div'); |
| progressBarIndicator.className = 'progress-track'; |
| |
| var progressBar = this.element_.ownerDocument.createElement('div'); |
| progressBar.className = 'progress-bar'; |
| progressBar.appendChild(progressBarIndicator); |
| |
| var cancelButton = this.element_.ownerDocument.createElement('button'); |
| cancelButton.className = 'cancel'; |
| cancelButton.setAttribute('tabindex', '-1'); |
| |
| var progressFrame = this.element_.ownerDocument.createElement('div'); |
| progressFrame.className = 'progress-frame'; |
| progressFrame.appendChild(progressBar); |
| progressFrame.appendChild(cancelButton); |
| |
| var itemElement = this.element_.ownerDocument.createElement('li'); |
| itemElement.appendChild(label); |
| itemElement.appendChild(progressFrame); |
| |
| return itemElement; |
| }; |
| |
| /** |
| * Handles the transition end event of items. |
| * @param {Event} event Transition end event. |
| * @private |
| */ |
| ProgressCenterPanel.prototype.onItemTransitionEnd_ = function(event) { |
| var itemElement = event.target.parentNode.parentNode.parentNode; |
| if (!itemElement.hasAttribute('pre-complete') || |
| event.propertyName !== 'width') |
| return; |
| if (itemElement !== this.closeViewItem_) |
| this.openView_.removeChild(itemElement); |
| else |
| itemElement.removeAttribute('pre-complete'); |
| if (this.resetRequested_) |
| this.reset(); |
| }; |
| |
| /** |
| * Handles the click event. |
| * @param {Event} event Click event. |
| * @private |
| */ |
| ProgressCenterPanel.prototype.onClick_ = function(event) { |
| // Toggle button. |
| if (event.target.classList.contains('toggle') && |
| (!this.closeView_.classList.contains('single') || |
| this.element_.classList.contains('opened'))) { |
| this.element_.classList.toggle('opened'); |
| return; |
| } |
| |
| // Cancel button. |
| if (this.cancelCallback) |
| this.cancelCallback( |
| event.target.parentNode.parentNode.getAttribute('data-progress-id')); |
| }; |