Files
vscode/src/vs/base/browser/ui/progressbar/progressbar.ts
T
2018-03-02 16:48:22 +01:00

228 lines
5.8 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./progressbar';
import { TPromise, ValueCallback } from 'vs/base/common/winjs.base';
import assert = require('vs/base/common/assert');
import { Builder, $ } from 'vs/base/browser/builder';
import DOM = require('vs/base/browser/dom');
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
const css_done = 'done';
const css_active = 'active';
const css_infinite = 'infinite';
const css_discrete = 'discrete';
const css_progress_container = 'monaco-progress-container';
const css_progress_bit = 'progress-bit';
export interface IProgressBarOptions extends IProgressBarStyles {
}
export interface IProgressBarStyles {
progressBarBackground?: Color;
}
const defaultOpts = {
progressBarBackground: Color.fromHex('#0E70C0')
};
/**
* A progress bar with support for infinite or discrete progress.
*/
export class ProgressBar {
private options: IProgressBarOptions;
private toUnbind: IDisposable[];
private workedVal: number;
private element: Builder;
private bit: HTMLElement;
private totalWork: number;
private animationStopToken: ValueCallback;
private progressBarBackground: Color;
constructor(container: Builder, options?: IProgressBarOptions);
constructor(container: HTMLElement, options?: IProgressBarOptions);
constructor(container: any, options?: IProgressBarOptions) {
this.options = options || Object.create(null);
mixin(this.options, defaultOpts, false);
this.toUnbind = [];
this.workedVal = 0;
this.progressBarBackground = this.options.progressBarBackground;
this.create(container);
}
private create(container: Builder): void;
private create(container: HTMLElement): void;
private create(container: any): void {
$(container).div({ 'class': css_progress_container }, (builder) => {
this.element = builder.clone();
builder.div({ 'class': css_progress_bit }).on([DOM.EventType.ANIMATION_START, DOM.EventType.ANIMATION_END, DOM.EventType.ANIMATION_ITERATION], (e: Event) => {
switch (e.type) {
case DOM.EventType.ANIMATION_ITERATION:
if (this.animationStopToken) {
this.animationStopToken(null);
}
break;
}
}, this.toUnbind);
this.bit = builder.getHTMLElement();
});
this.applyStyles();
}
private off(): void {
this.bit.style.width = 'inherit';
this.bit.style.opacity = '1';
this.element.removeClass(css_active);
this.element.removeClass(css_infinite);
this.element.removeClass(css_discrete);
this.workedVal = 0;
this.totalWork = undefined;
}
/**
* Indicates to the progress bar that all work is done.
*/
public done(): ProgressBar {
return this.doDone(true);
}
/**
* Stops the progressbar from showing any progress instantly without fading out.
*/
public stop(): ProgressBar {
return this.doDone(false);
}
private doDone(delayed: boolean): ProgressBar {
this.element.addClass(css_done);
// let it grow to 100% width and hide afterwards
if (!this.element.hasClass(css_infinite)) {
this.bit.style.width = 'inherit';
if (delayed) {
TPromise.timeout(200).then(() => this.off());
} else {
this.off();
}
}
// let it fade out and hide afterwards
else {
this.bit.style.opacity = '0';
if (delayed) {
TPromise.timeout(200).then(() => this.off());
} else {
this.off();
}
}
return this;
}
/**
* Use this mode to indicate progress that has no total number of work units.
*/
public infinite(): ProgressBar {
this.bit.style.width = '2%';
this.bit.style.opacity = '1';
this.element.removeClass(css_discrete);
this.element.removeClass(css_done);
this.element.addClass(css_active);
this.element.addClass(css_infinite);
return this;
}
/**
* Tells the progress bar the total number of work. Use in combination with workedVal() to let
* the progress bar show the actual progress based on the work that is done.
*/
public total(value: number): ProgressBar {
this.workedVal = 0;
this.totalWork = value;
return this;
}
/**
* Finds out if this progress bar is configured with total work
*/
public hasTotal(): boolean {
return !isNaN(this.totalWork);
}
/**
* Tells the progress bar that an amount of work has been completed.
*/
public worked(value: number): ProgressBar {
assert.ok(!isNaN(this.totalWork), 'Total work not set');
value = Number(value);
assert.ok(!isNaN(value), 'Value is not a number');
value = Math.max(1, value);
this.workedVal += value;
this.workedVal = Math.min(this.totalWork, this.workedVal);
if (this.element.hasClass(css_infinite)) {
this.element.removeClass(css_infinite);
}
if (this.element.hasClass(css_done)) {
this.element.removeClass(css_done);
}
if (!this.element.hasClass(css_active)) {
this.element.addClass(css_active);
}
if (!this.element.hasClass(css_discrete)) {
this.element.addClass(css_discrete);
}
this.bit.style.width = 100 * (this.workedVal / this.totalWork) + '%';
return this;
}
/**
* Returns the builder this progress bar is building in.
*/
public getContainer(): Builder {
return $(this.element);
}
public style(styles: IProgressBarStyles): void {
this.progressBarBackground = styles.progressBarBackground;
this.applyStyles();
}
protected applyStyles(): void {
if (this.bit) {
const background = this.progressBarBackground ? this.progressBarBackground.toString() : null;
this.bit.style.backgroundColor = background;
}
}
public dispose(): void {
this.toUnbind = dispose(this.toUnbind);
}
}