/** xhr-progress.js
* Minimalistic progress bar for XHR/AJAX requests etc.
* (C) 2018 Rob Kluver. MIT License.
* Dependencies: jQuery >= 1.12.4
*/
"use strict";
var XhrProgress =
(function (options){
/**
* @param {object} Set options:
* parent: Parent element
* height: Height [px]
* delay: Time to wait until the progress bar is shown after start() is called [not implemented][ms]
* color: Color of progress bar
* colorFailed: Color of progress bar if failed()
* style: Box shadow style of bar
* styleFailed: Box shadow style of bar
* paddingTop: Add some whitespace above the progress bar [px]
* fadeOutDuration: Once complete, fade out the progress bar during given interval [ms]
*/
if (options == null){
options = {};
}
var defaults = {
parent: '#xhr-progress',
height: 2,
delay: 1500,
color: '#77b6ff',
colorFailed: '#ff4f4f',
style: '0 0 10px rgba(119, 182, 255, 0.7)',
styleFailed: '0 0 10px rgba(255, 119, 119, 0.7)',
paddingTop: 0,
fadeOutDuration: 400,
};
var initial = Object.assign({}, defaults, options);
var current = Object.assign({}, initial);
var visible = false;
var renderedParams = {};
/**
* (Internal) Generate html to render progress bar
* @returns {string}
*/
function template(percent, height, color, style, paddingTop){
var paddingTopHtml = paddingTop == null ? '' : `padding-top: ${paddingTop}px;`;
return `
` +
`
`;
}
/**
* (Internal) Check if the progress bar elements have been added to DOM.
* @returns {bool} True if created
*/
function isRendered(){
return $('#xhr-progress > div > div > div').length === 1;
}
/**
* (Internal) Update the progress bar.
* @param {bool} Tru if OK, false if failed condition [default: true]
* @returns {void}
*/
function render(isOk){
if (visible){
if (isOk !== false){
renderProgressBar(current.percent, current.height, current.color, current.style, current.paddingTop);
}
else{
renderProgressBar(current.percent, current.height, current.colorFailed, current.styleFailed, current.paddingTop);
}
}
else{
$(current.parent).html("");
}
function renderProgressBar(percent, height, color, style, paddingTop){
var paramsChanged = false;
if (height !== renderedParams.height ||
color !== renderedParams.color ||
style !== renderedParams.style){
paramsChanged = true;
renderedParams = {height, color, style};
}
var test = false;
if (!isRendered() || paramsChanged || test){
$(current.parent).html(template(percent, height, color, style, paddingTop));
}
else{
$(current.parent).find('div>div>div').width(`${current.percent.toFixed(0)}%`);
}
}
}
/**
* (Internal) Compress value so that returned value never exceeds 100:
* x = 100 yields 68%; Inf yields 100%.
*
* @param {number} Value 0-Inf
* @returns {number} Value 0...100
*/
function compress(x){
return 100*(1-1/Math.pow(10,x/200));
}
/**
* Shows the progress bar (as soon as delay has elapsed).
*
* @param {bool} If true, assume progress is made without calling
* trickle()/increment()/set() [not implemented]
* @param {number} If auto, specify expected duration until complete in
* ms[default: 5000] [not implemented]
* @returns {void}
*/
function start(auto, duration){
visible = true;
if (auto === true){
current.percent = 15;
if (duration == null){
duration = 5000;
}
}
else{
current.percent = 0;
}
current.auto = auto === true;
render();
}
/**
* Incremental progress (random) will never reach 100%.
*
* @returns {void}
*/
function trickle(){
current.percent += 5 + Math.random() * 10;
render();
}
/**
* Incremental progress (sum of deltas <= 100).
*
* @returns {void}
*/
function increment(delta){
current.percent += delta;
current.percent = Math.min(current.percent, 100);
render();
}
/**
* Incremental progress (sum of deltas <= 100).
*
* @returns {void}
*/
function set(percent){
current.percent = Math.min(percent, 100);
render();
}
/**
* Get current value of progress bar (percent).
*
* @returns {number}
*/
function get(){
return current.percent;
}
/**
* Indicate a failed request (bar canges to colorFailed then disappears).
*
* @returns {void}
*/
function fail(fnFailed){
var final = JSON.parse(JSON.stringify(current));
debugger;
render(false);
$(current.parent).children().first().delay(700).fadeOut(current.fadeOutDuration, function(){
visible = false;
render();
if (typeof func === "function"){
func(final);
}
});
}
/**
* Sets the progress to 100% then fades out.
* @param {function} Complete function. Final state object passed in as parameter.
* @returns {void}
*/
function complete(fnComplete){
current.percent = 100;
var final = JSON.parse(JSON.stringify(current));
render();
$(current.parent).children().first().fadeOut(current.fadeOutDuration, function(){
visible = false;
render();
if (typeof func === "function"){
func(final);
}
});
}
function visible(){
return visible;
}
return {start, trickle, increment, set, get, fail, complete, visible};
});