/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import 'vs/css!./progressbar'; import { Disposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; import { hide, show } from 'vs/base/browser/dom'; import { RunOnceScheduler } from 'vs/base/common/async'; import { isNumber } from 'vs/base/common/types'; const CSS_DONE = 'done'; const CSS_ACTIVE = 'active'; const CSS_INFINITE = 'infinite'; const CSS_DISCRETE = 'discrete'; 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 extends Disposable { private options: IProgressBarOptions; private workedVal: number; private element!: HTMLElement; private bit!: HTMLElement; private totalWork: number | undefined; private progressBarBackground: Color | undefined; private showDelayedScheduler: RunOnceScheduler; constructor(container: HTMLElement, options?: IProgressBarOptions) { super(); this.options = options || Object.create(null); mixin(this.options, defaultOpts, false); this.workedVal = 0; this.progressBarBackground = this.options.progressBarBackground; this._register(this.showDelayedScheduler = new RunOnceScheduler(() => show(this.element), 0)); this.create(container); } private create(container: HTMLElement): void { this.element = document.createElement('div'); this.element.classList.add('monaco-progress-container'); this.element.setAttribute('role', 'progressbar'); container.appendChild(this.element); this.bit = document.createElement('div'); this.bit.classList.add('progress-bit'); this.element.appendChild(this.bit); this.applyStyles(); } private off(): void { this.bit.style.width = 'inherit'; this.bit.style.opacity = '1'; this.element.classList.remove(CSS_ACTIVE, CSS_INFINITE, CSS_DISCRETE); this.workedVal = 0; this.totalWork = undefined; } /** * Indicates to the progress bar that all work is done. */ done(): ProgressBar { return this.doDone(true); } /** * Stops the progressbar from showing any progress instantly without fading out. */ stop(): ProgressBar { return this.doDone(false); } private doDone(delayed: boolean): ProgressBar { this.element.classList.add(CSS_DONE); // let it grow to 100% width and hide afterwards if (!this.element.classList.contains(CSS_INFINITE)) { this.bit.style.width = 'inherit'; if (delayed) { setTimeout(() => this.off(), 200); } else { this.off(); } } // let it fade out and hide afterwards else { this.bit.style.opacity = '0'; if (delayed) { setTimeout(() => this.off(), 200); } else { this.off(); } } return this; } /** * Use this mode to indicate progress that has no total number of work units. */ infinite(): ProgressBar { this.bit.style.width = '2%'; this.bit.style.opacity = '1'; this.element.classList.remove(CSS_DISCRETE, CSS_DONE); this.element.classList.add(CSS_ACTIVE, 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. */ total(value: number): ProgressBar { this.workedVal = 0; this.totalWork = value; this.element.setAttribute('aria-valuemax', value.toString()); return this; } /** * Finds out if this progress bar is configured with total work */ hasTotal(): boolean { return isNumber(this.totalWork); } /** * Tells the progress bar that an increment of work has been completed. */ worked(value: number): ProgressBar { value = Math.max(1, Number(value)); return this.doSetWorked(this.workedVal + value); } /** * Tells the progress bar the total amount of work that has been completed. */ setWorked(value: number): ProgressBar { value = Math.max(1, Number(value)); return this.doSetWorked(value); } private doSetWorked(value: number): ProgressBar { const totalWork = this.totalWork || 100; this.workedVal = value; this.workedVal = Math.min(totalWork, this.workedVal); this.element.classList.remove(CSS_INFINITE, CSS_DONE); this.element.classList.add(CSS_ACTIVE, CSS_DISCRETE); this.element.setAttribute('aria-valuenow', value.toString()); this.bit.style.width = 100 * (this.workedVal / (totalWork)) + '%'; return this; } getContainer(): HTMLElement { return this.element; } show(delay?: number): void { this.showDelayedScheduler.cancel(); if (typeof delay === 'number') { this.showDelayedScheduler.schedule(delay); } else { show(this.element); } } hide(): void { hide(this.element); this.showDelayedScheduler.cancel(); } style(styles: IProgressBarStyles): void { this.progressBarBackground = styles.progressBarBackground; this.applyStyles(); } protected applyStyles(): void { if (this.bit) { const background = this.progressBarBackground ? this.progressBarBackground.toString() : ''; this.bit.style.backgroundColor = background; } } }