Source: ui/progress.bar.js

/**
 * @module stb/ui/progress.bar
 * @author Igor Zaporozhets <deadbyelpy@gmail.com>
 * @license GNU GENERAL PUBLIC LICENSE Version 3
 */

'use strict';

var Component = require('../component');


/**
 * Base progress bar implementation.
 *
 * @constructor
 * @extends Component
 *
 * @param {Object} [config={}] init parameters (all inherited from the parent)
 * @param {number} [config.value=0] initial value
 * @param {number} [config.max=100] max progress value
 * @param {number} [config.min=0] min progress value
 *
 * @example
 * var ProgressBar = require('stb/ui/progress.bar'),
 *     progressBar = new ProgressBar({
 *         min: -100,
 *         max:  200,
 *         events: {
 *             done: function () {
 *                 debug.log('ProgressBar: done');
 *             },
 *             change: function ( data ) {
 *                 debug.log('ProgressBar: change to ' + data.curr + ' from ' + data.prev);
 *             }
 *         }
 *     });
 */
function ProgressBar ( config ) {
	// sanitize
	config = config || {};

	/**
	 * Max progress value.
	 *
	 * @type {number}
	 */
	this.max = 100;

	/**
	 * Min progress value.
	 *
	 * @type {number}
	 */
	this.min = 0;

	/**
	 * Initial progress position.
	 *
	 * @type {number}
	 */
	this.value = 0;

	/**
	 * Value of the one percent step
	 *
	 * @type {number}
	 */
	this.step = 1;

	// can't accept focus
	config.focusable = config.focusable || false;

	// parent init
	Component.call(this, config);

	// create $body if not provided
	if ( this.$node === this.$body ) {
		// insert bar line
		this.$body = this.$node.appendChild(document.createElement('div'));
	}

	// correct CSS class names
	this.$node.classList.add('progressBar');
	this.$body.classList.add('value');

	// component setup
	this.init(config);
}


// inheritance
ProgressBar.prototype = Object.create(Component.prototype);
ProgressBar.prototype.constructor = ProgressBar;


/**
 * Set position of the given value.
 * Does nothing in case when progress is end and passed value is more than max value.
 *
 * @param {number} value new value to set
 * @return {boolean} operation result
 *
 * @fires module:stb/ui/progress.bar~ProgressBar#done
 * @fires module:stb/ui/progress.bar~ProgressBar#change
 */
ProgressBar.prototype.set = function ( value ) {
	var prevValue = this.value;

	if ( DEBUG ) {
		if ( arguments.length !== 1 ) { throw 'wrong arguments number'; }
	}

	// value changed but in the given range
	if ( this.value !== value && value <= this.max && value >= this.min ) {
		if ( DEBUG ) {
			if ( Number(value) !== value ) { throw 'value must be a number'; }
		}

		// set new value
		this.value = value;

		// get value in percents
		value = Math.abs(this.value - this.min) / this.step;

		if ( value === 100 ) {
			// there are some listeners
			if ( this.events['done'] !== undefined ) {
				/**
				 * Set progress to its maximum value.
				 *
				 * @event module:stb/ui/progress.bar~ProgressBar#done
				 */
				this.emit('done');
			}
		}

		// set progress bar width
		this.$body.style.width = value + '%';

		// there are some listeners
		if ( this.events['change'] !== undefined ) {
			/**
			 * Update progress value.
			 *
			 * @event module:stb/ui/progress.bar~ProgressBar#change
			 *
			 * @type {Object}
			 * @property {number} prev old/previous progress value
			 * @property {number} curr new/current progress value
			 */
			this.emit('change', {curr: this.value, prev: prevValue});
		}

		return true;
	}

	return false;
};


/**
 * Init or re-init current max or/and min or/and value.
 *
 * @param {Object} config init parameters (subset of constructor config params)
 */
ProgressBar.prototype.init = function ( config ) {
	if ( DEBUG ) {
		if ( arguments.length !== 1 ) { throw 'wrong arguments number'; }
		if ( typeof config !== 'object' ) { throw 'wrong config type'; }
	}

	// set max progress value
	if ( config.max !== undefined ) {
		if ( DEBUG ) {
			if ( Number(config.max) !== config.max ) { throw 'config.max value must be a number'; }
		}
		// apply
		this.max = config.max;
	}

	// set min progress value
	if ( config.min !== undefined ) {
		if ( DEBUG ) {
			if ( Number(config.min) !== config.min ) { throw 'config.min value must be a number'; }
		}
		// apply
		this.min = config.min;
	}

	if ( DEBUG ) {
		if ( this.min >= this.max ) { throw 'this.min value must be less than this.max'; }
	}

	// set actual progress value
	if ( config.value !== undefined ) {
		if ( DEBUG ) {
			if ( Number(config.value) !== config.value ) { throw 'config.value must be a number'; }
			if ( config.value > this.max ) { throw 'config.value more than config.maximum'; }
			if ( config.value < this.min ) { throw 'config.value less than config.minimum'; }
		}
		// apply
		this.value = config.value;
	}

	this.step = Math.abs(this.max - this.min) / 100;

	// init bar size, (this.min - this.value) - calculate distance from start
	this.$body.style.width = (Math.abs(this.min - this.value) / this.step) + '%';
};


// public
module.exports = ProgressBar;