| Index: chrome/browser/resources/file_manager/foreground/js/progress_center_item_group.js
|
| diff --git a/chrome/browser/resources/file_manager/foreground/js/progress_center_item_group.js b/chrome/browser/resources/file_manager/foreground/js/progress_center_item_group.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a178ba7458fb20042047b8b99da3ca4cdcf8e174
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/file_manager/foreground/js/progress_center_item_group.js
|
| @@ -0,0 +1,414 @@
|
| +// 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';
|
| +
|
| +/**
|
| + * Group of progress item in the progress center panels.
|
| + *
|
| + * This is responsible for generating the summarized item and managing lifetime
|
| + * of error items.
|
| + * @param {string} name Name of the group.
|
| + * @constructor
|
| + */
|
| +function ProgressCenterItemGroup(name) {
|
| + /**
|
| + * Name of the group.
|
| + * @type {string}
|
| + */
|
| + this.name = name;
|
| +
|
| + /**
|
| + * State of the group.
|
| + * @type {ProgressCenterItemGroup.State}
|
| + * @private
|
| + */
|
| + this.state_ = ProgressCenterItemGroup.State.EMPTY;
|
| +
|
| + /**
|
| + * Items that are progressing, or completed but still animated.
|
| + * Key is item ID.
|
| + * @type {Object.<string, ProgressCenterItem>}
|
| + * @private
|
| + */
|
| + this.items_ = {};
|
| +
|
| + /**
|
| + * Set of animated state of items. Key is item ID and value is whether the
|
| + * item is animated or not.
|
| + * @type {Object.<string, boolean>}
|
| + * @private
|
| + */
|
| + this.animated_ = {};
|
| +
|
| + /**
|
| + * Last summarized item.
|
| + * @type {ProgressCenterItem}
|
| + * @private
|
| + */
|
| + this.summarizedItem_ = null;
|
| +
|
| + /**
|
| + * Whether the summarized item is animated or not.
|
| + * @type {boolean}
|
| + * @private
|
| + */
|
| + this.summarizedItemAnimated_ = false;
|
| +
|
| + /**
|
| + * Total maximum progress value of items already completed and removed from
|
| + * this.items_.
|
| + * @type {number}
|
| + * @private
|
| + */
|
| + this.totalProgressMax_ = 0;
|
| +
|
| + /**
|
| + * Total progress value of items already completed and removed from
|
| + * this.items_.
|
| + * @type {number}
|
| + * @private
|
| + */
|
| + this.totalProgressValue_ = 0;
|
| +
|
| + Object.seal(this);
|
| +}
|
| +
|
| +/**
|
| + * State of ProgressCenterItemGroup.
|
| + * @enum {string}
|
| + * @const
|
| + */
|
| +ProgressCenterItemGroup.State = Object.freeze({
|
| + // Group has no items.
|
| + EMPTY: 'empty',
|
| + // Group has at least 1 progressing item.
|
| + ACTIVE: 'active',
|
| + // Group has no progressing items but still shows error items.
|
| + INACTIVE: 'inactive'
|
| +});
|
| +
|
| +/**
|
| + * Makes the summarized item for the groups.
|
| + *
|
| + * When a group has only error items, getSummarizedItem of the item returns
|
| + * null. Basically the first result of the groups that the progress center panel
|
| + * contains is used as a summarized item. But If all the group returns null, the
|
| + * progress center panel generates the summarized item by using the method.
|
| + *
|
| + * @param {Array.<ProgressCenterItemGroup>} var_groups List of groups.
|
| + * @return {ProgressCenterItem} Summarized item.
|
| + */
|
| +ProgressCenterItemGroup.getSummarizedErrorItem = function(var_groups) {
|
| + var groups = Array.prototype.slice.call(arguments);
|
| + var errorItems = [];
|
| + for (var i = 0; i < groups.length; i++) {
|
| + for (var id in groups[i].items_) {
|
| + var item = groups[i].items_[id];
|
| + if (item.state === ProgressItemState.ERROR)
|
| + errorItems.push(item);
|
| + }
|
| + }
|
| + if (errorItems.length === 0)
|
| + return null;
|
| +
|
| + if (errorItems.length === 1)
|
| + return errorItems[0].clone();
|
| +
|
| + var item = new ProgressCenterItem();
|
| + item.state = ProgressItemState.ERROR;
|
| + item.message = strf('ERROR_PROGRESS_SUMMARY_PLURAL',
|
| + errorItems.length);
|
| + return item;
|
| +};
|
| +
|
| +/**
|
| + * Obtains Whether the item should be animated or not.
|
| + * @param {boolean} previousAnimated Whether the item is previously animated or
|
| + * not.
|
| + * @param {ProgressCenterItem} previousItem Item before updating.
|
| + * @param {ProgressCenterItem} item New item.
|
| + * @return {boolean} Whether the item should be animated or not.
|
| + * @private
|
| + */
|
| +ProgressCenterItemGroup.shouldAnimate_ = function(
|
| + previousAnimated, previousItem, item) {
|
| + if (!previousItem)
|
| + return false;
|
| + if (!item)
|
| + return false;
|
| + if (previousItem.progressRateInPercent < item.progressRateInPercent)
|
| + return true;
|
| + if (previousAnimated &&
|
| + previousItem.progressRateInPercent === item.progressRateInPercent)
|
| + return true;
|
| + return false;
|
| +};
|
| +
|
| +ProgressCenterItemGroup.prototype = {
|
| + /**
|
| + * @return {ProgressCenterItemGroup.State} State of the group.
|
| + */
|
| + get state() {
|
| + return this.state_;
|
| + },
|
| +
|
| + /**
|
| + * @return {number} Number of error items that the group contains.
|
| + */
|
| + get numErrors() {
|
| + var result = 0;
|
| + for (var id in this.items_) {
|
| + if (this.items_[id].state === ProgressItemState.ERROR)
|
| + result++;
|
| + }
|
| + return result;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Obtains the progressing (or completed but animated) item.
|
| + *
|
| + * @param {string} id Item ID.
|
| + * @return {ProgressCenterItem} Item having the ID.
|
| + */
|
| +ProgressCenterItemGroup.prototype.getItem = function(id) {
|
| + return this.items_[id] || null;
|
| +};
|
| +
|
| +/**
|
| + * Obtains whether the item should be animated or not.
|
| + * @param {string} id Item ID.
|
| + * @return {boolean} Whether the item should be animated or not.
|
| + */
|
| +ProgressCenterItemGroup.prototype.isAnimated = function(id) {
|
| + return !!this.animated_[id];
|
| +};
|
| +
|
| +/**
|
| + * Obtains whether the summarized item should be animated or not.
|
| + * @return {boolean} Whether the summarized item should be animated or not.
|
| + */
|
| +ProgressCenterItemGroup.prototype.isSummarizedAnimated = function() {
|
| + return this.summarizedItemAnimated_;
|
| +};
|
| +
|
| +/**
|
| + * Starts item update.
|
| + * Marks the given item as updating.
|
| + * @param {ProgressCenterItem} item Item containing updated information.
|
| + */
|
| +ProgressCenterItemGroup.prototype.update = function(item) {
|
| + // If the group is inactive, go back to the empty state.
|
| + this.endInactive();
|
| +
|
| + // Compares the current state and the new state to check if the update is
|
| + // valid or not.
|
| + var previousItem = this.items_[item.id];
|
| + switch (item.state) {
|
| + case ProgressItemState.ERROR:
|
| + if (previousItem && previousItem.state !== ProgressItemState.PROGRESSING)
|
| + return;
|
| + if (this.state_ === ProgressCenterItemGroup.State.EMPTY)
|
| + this.state_ = ProgressCenterItemGroup.State.INACTIVE;
|
| + this.items_[item.id] = item.clone();
|
| + this.animated_[item.id] = false;
|
| + break;
|
| +
|
| + case ProgressItemState.PROGRESSING:
|
| + case ProgressItemState.COMPLETED:
|
| + if ((!previousItem && item.state === ProgressItemState.COMPLETED) ||
|
| + (previousItem &&
|
| + previousItem.state !== ProgressItemState.PROGRESSING))
|
| + return;
|
| + if (this.state_ === ProgressCenterItemGroup.State.EMPTY)
|
| + this.state_ = ProgressCenterItemGroup.State.ACTIVE;
|
| + this.items_[item.id] = item.clone();
|
| + this.animated_[item.id] = ProgressCenterItemGroup.shouldAnimate_(
|
| + !!this.animated_[item.id],
|
| + previousItem,
|
| + item);
|
| + if (!this.animated_[item.id])
|
| + this.completeItemAnimation(item.id);
|
| + break;
|
| +
|
| + case ProgressItemState.CANCELED:
|
| + if (!previousItem ||
|
| + previousItem.state !== ProgressItemState.PROGRESSING)
|
| + return;
|
| + delete this.items_[item.id];
|
| + this.animated_[item.id] = false;
|
| + this.summarizedItem_ = null;
|
| + }
|
| +
|
| + // Update the internal summarized item cache.
|
| + var previousSummarizedItem = this.summarizedItem_;
|
| + this.summarizedItem_ = this.getSummarizedItem(0);
|
| + this.summarizedItemAnimated_ = ProgressCenterItemGroup.shouldAnimate_(
|
| + !!this.summarizedItemAnimated_,
|
| + previousSummarizedItem,
|
| + this.summarizedItem_);
|
| + if (!this.summarizedItemAnimated_)
|
| + this.completeSummarizedItemAnimation();
|
| +};
|
| +
|
| +/**
|
| + * Notifies the end of the item's animation to the group.
|
| + * If all the items except error items completes, the group enter the inactive
|
| + * state.
|
| + * @param {string} id Item ID.
|
| + */
|
| +ProgressCenterItemGroup.prototype.completeItemAnimation = function(id) {
|
| + if (this.state_ !== ProgressCenterItemGroup.State.ACTIVE)
|
| + return;
|
| +
|
| + this.animated_[id] = false;
|
| + if (this.items_[id].state === ProgressItemState.COMPLETED) {
|
| + this.totalProgressValue_ += (this.items_[id].progressValue || 0.0);
|
| + this.totalProgressMax_ += (this.items_[id].progressMax || 0.0);
|
| + delete this.items_[id];
|
| + this.tryEndActive_();
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Notifies the end of the summarized item's animation.
|
| + * This may update summarized view. (1 progressing + 1 error -> 1 error)
|
| + */
|
| +ProgressCenterItemGroup.prototype.completeSummarizedItemAnimation = function() {
|
| + this.summarizedItemAnimated_ = false;
|
| + this.tryEndActive_();
|
| +};
|
| +
|
| +/**
|
| + * Obtains the summary of the set.
|
| + * @param {number} numOtherErrors Number of errors contained by other groups.
|
| + * @return {ProgressCenterItem} Item.
|
| + */
|
| +ProgressCenterItemGroup.prototype.getSummarizedItem =
|
| + function(numOtherErrors) {
|
| + if (this.state_ === ProgressCenterItemGroup.State.EMPTY ||
|
| + this.state_ === ProgressCenterItemGroup.State.INACTIVE)
|
| + return null;
|
| +
|
| + var summarizedItem = new ProgressCenterItem();
|
| + summarizedItem.progressMax += this.totalProgressMax_;
|
| + summarizedItem.progressValue += this.totalProgressValue_;
|
| + var progressingItems = [];
|
| + var errorItems = [];
|
| + var numItems = 0;
|
| +
|
| + for (var id in this.items_) {
|
| + var item = this.items_[id];
|
| + numItems++;
|
| +
|
| + // Count states.
|
| + switch (item.state) {
|
| + case ProgressItemState.PROGRESSING:
|
| + case ProgressItemState.COMPLETED:
|
| + progressingItems.push(item);
|
| + break;
|
| + case ProgressItemState.ERROR:
|
| + errorItems.push(item);
|
| + continue;
|
| + }
|
| +
|
| + // If all of the progressing items have the same type, then use
|
| + // it. Otherwise use TRANSFER, since it is the most generic.
|
| + if (summarizedItem.type === null)
|
| + summarizedItem.type = item.type;
|
| + else if (summarizedItem.type !== item.type)
|
| + summarizedItem.type = ProgressItemType.TRANSFER;
|
| +
|
| + // Sum up the progress values.
|
| + summarizedItem.progressMax += item.progressMax;
|
| + summarizedItem.progressValue += item.progressValue;
|
| + }
|
| +
|
| + // Returns 1 item.
|
| + if (progressingItems.length === 1 &&
|
| + errorItems.length + numOtherErrors === 0) {
|
| + summarizedItem.id = progressingItems[0].id;
|
| + summarizedItem.cancelCallback = progressingItems[0].cancelCallback;
|
| + summarizedItem.message = progressingItems[0].message;
|
| + summarizedItem.state = progressingItems[0].state;
|
| + return summarizedItem;
|
| + }
|
| +
|
| + // Returns integrated items.
|
| + if (progressingItems.length > 0) {
|
| + var messages = [];
|
| + switch (summarizedItem.type) {
|
| + case ProgressItemType.COPY:
|
| + messages.push(str('COPY_PROGRESS_SUMMARY'));
|
| + break;
|
| + case ProgressItemType.MOVE:
|
| + messages.push(str('MOVE_PROGRESS_SUMMARY'));
|
| + break;
|
| + case ProgressItemType.DELETE:
|
| + messages.push(str('DELETE_PROGRESS_SUMMARY'));
|
| + break;
|
| + case ProgressItemType.ZIP:
|
| + messages.push(str('ZIP_PROGRESS_SUMMARY'));
|
| + break;
|
| + case ProgressItemType.TRANSFER:
|
| + messages.push(str('TRANSFER_PROGRESS_SUMMARY'));
|
| + break;
|
| + }
|
| + var numErrors = errorItems.length + numOtherErrors;
|
| + if (numErrors === 1)
|
| + messages.push(str('ERROR_PROGRESS_SUMMARY'));
|
| + else if (numErrors > 1)
|
| + messages.push(strf('ERROR_PROGRESS_SUMMARY_PLURAL', numErrors));
|
| + summarizedItem.summarized = true;
|
| + summarizedItem.message = messages.join(' ');
|
| + summarizedItem.state = ProgressItemState.PROGRESSING;
|
| + return summarizedItem;
|
| + }
|
| +
|
| + // Retruns error.
|
| + if (errorItems.length > 0)
|
| + return null;
|
| +
|
| + // Returns complete items.
|
| + summarizedItem.state = ProgressItemState.COMPLETED;
|
| + return summarizedItem;
|
| +};
|
| +
|
| +/**
|
| + * Goes back to the EMPTY state from the INACTIVE state. Removes all the items.
|
| + * If the current state is not the INACTIVE, nothing happens.
|
| + */
|
| +ProgressCenterItemGroup.prototype.endInactive = function() {
|
| + if (this.state_ !== ProgressCenterItemGroup.State.INACTIVE)
|
| + return;
|
| + this.items_ = {};
|
| + this.animated_ = {};
|
| + this.summarizedItem_ = null;
|
| + this.summarizedItemAnimated_ = false;
|
| + this.totalProgressValue_ = 0.0;
|
| + this.totalProgressMax_ = 0.0;
|
| + this.state_ = ProgressCenterItemGroup.State.EMPTY;
|
| +};
|
| +
|
| +/**
|
| + * Ends active state if there is no progressing and animated items.
|
| + * @private
|
| + */
|
| +ProgressCenterItemGroup.prototype.tryEndActive_ = function() {
|
| + if (this.state_ !== ProgressCenterItemGroup.State.ACTIVE ||
|
| + this.summarizedItemAnimated_)
|
| + return;
|
| + var hasError = false;
|
| + for (var id in this.items_) {
|
| + // If there is non-error item (progressing, or completed but still
|
| + // animated), we should stay the active state.
|
| + if (this.items_[id].state !== ProgressItemState.ERROR)
|
| + return;
|
| + hasError = true;
|
| + }
|
| + this.state_ = ProgressCenterItemGroup.State.INACTIVE;
|
| + if (!hasError)
|
| + this.endInactive();
|
| +};
|
|
|