Skip to main content
formatting
Source Link
Flambino
  • 33.3k
  • 2
  • 46
  • 90
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var goBack = function(step){
    //cache current form or whatever
    pbar.goToStep(step);
};

var pbar = new progressBar({
    id:"#ProgressBar",
    steps:["Date","Items","Preview","Details","Confirm"],
    previousClicked:function(step){goBack(step);}
});
$("#next").on("click",function(){pbar.next()});
$("#previous").on("click",function(){pbar.previous()});
var goBack = function(step){
    //cache current form or whatever
    pbar.goToStep(step);
};

var pbar = new progressBar({
    id:"#ProgressBar",
    steps:["Date","Items","Preview","Details","Confirm"],
    previousClicked:function(step){goBack(step);}
});
$("#next").on("click",function(){pbar.next()});
$("#previous").on("click",function(){pbar.previous()});
ol.progressbar {
    list-style-type: none;
    padding-left:0;
}
.progressbar.container {
    display: flex;
    align-items: flex-end;
    padding-top: 22px;
}
.progressbar .step {
    flex-grow:1;
    position:relative;
    text-align: center;
    z-index:1;
}
.progressbar .step-number {
    position:relative;
    z-index:10;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color:white;
    display:inline-block;
    text-align: center;
    line-height: 20px;
    border:1px solid;
}
.progressbar .step-finished .step-number:hover{
    background-color: lightblue;
    cursor: pointer;
}
.progressbar .step-finished .step-number{
    background-color: green;
}
.progressbar .step-current .step-number{
    background-color:lightblue;
}
.progressbar .step-label-wrap {
    position: absolute;
    width:100%;
    top: -22px;
}
.progressbar .step-label {
    padding: 0px 1px;
}
.progressbar .step-line {
    height: 2px;
    background-color: black;
    width:100%;
    position:absolute;
    top: 50%;
    left:50%;
    z-index:5;
}
.progressbar .step:last-of-type .step-line{
    display:none;
}
ol.progressbar {
    list-style-type: none;
    padding-left:0;
}
.progressbar.container {
    display: flex;
    align-items: flex-end;
    padding-top: 22px;
}
.progressbar .step {
    flex-grow:1;
    position:relative;
    text-align: center;
    z-index:1;
}
.progressbar .step-number {
    position:relative;
    z-index:10;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color:white;
    display:inline-block;
    text-align: center;
    line-height: 20px;
    border:1px solid;
}
.progressbar .step-finished .step-number:hover{
    background-color: lightblue;
    cursor: pointer;
}
.progressbar .step-finished .step-number{
    background-color: green;
}
.progressbar .step-current .step-number{
    background-color:lightblue;
}
.progressbar .step-label-wrap {
    position: absolute;
    width:100%;
    top: -22px;
}
.progressbar .step-label {
    padding: 0px 1px;
}
.progressbar .step-line {
    height: 2px;
    background-color: black;
    width:100%;
    position:absolute;
    top: 50%;
    left:50%;
    z-index:5;
}
.progressbar .step:last-of-type .step-line{
    display:none;
}
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var goBack = function(step){
    //cache current form or whatever
    pbar.goToStep(step);
};

var pbar = new progressBar({
    id:"#ProgressBar",
    steps:["Date","Items","Preview","Details","Confirm"],
    previousClicked:function(step){goBack(step);}
});
$("#next").on("click",function(){pbar.next()});
$("#previous").on("click",function(){pbar.previous()});
ol.progressbar {
    list-style-type: none;
    padding-left:0;
}
.progressbar.container {
    display: flex;
    align-items: flex-end;
    padding-top: 22px;
}
.progressbar .step {
    flex-grow:1;
    position:relative;
    text-align: center;
    z-index:1;
}
.progressbar .step-number {
    position:relative;
    z-index:10;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color:white;
    display:inline-block;
    text-align: center;
    line-height: 20px;
    border:1px solid;
}
.progressbar .step-finished .step-number:hover{
    background-color: lightblue;
    cursor: pointer;
}
.progressbar .step-finished .step-number{
    background-color: green;
}
.progressbar .step-current .step-number{
    background-color:lightblue;
}
.progressbar .step-label-wrap {
    position: absolute;
    width:100%;
    top: -22px;
}
.progressbar .step-label {
    padding: 0px 1px;
}
.progressbar .step-line {
    height: 2px;
    background-color: black;
    width:100%;
    position:absolute;
    top: 50%;
    left:50%;
    z-index:5;
}
.progressbar .step:last-of-type .step-line{
    display:none;
}
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var goBack = function(step){
    //cache current form or whatever
    pbar.goToStep(step);
};

var pbar = new progressBar({
    id:"#ProgressBar",
    steps:["Date","Items","Preview","Details","Confirm"],
    previousClicked:function(step){goBack(step);}
});
$("#next").on("click",function(){pbar.next()});
$("#previous").on("click",function(){pbar.previous()});
ol.progressbar {
    list-style-type: none;
    padding-left:0;
}
.progressbar.container {
    display: flex;
    align-items: flex-end;
    padding-top: 22px;
}
.progressbar .step {
    flex-grow:1;
    position:relative;
    text-align: center;
    z-index:1;
}
.progressbar .step-number {
    position:relative;
    z-index:10;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color:white;
    display:inline-block;
    text-align: center;
    line-height: 20px;
    border:1px solid;
}
.progressbar .step-finished .step-number:hover{
    background-color: lightblue;
    cursor: pointer;
}
.progressbar .step-finished .step-number{
    background-color: green;
}
.progressbar .step-current .step-number{
    background-color:lightblue;
}
.progressbar .step-label-wrap {
    position: absolute;
    width:100%;
    top: -22px;
}
.progressbar .step-label {
    padding: 0px 1px;
}
.progressbar .step-line {
    height: 2px;
    background-color: black;
    width:100%;
    position:absolute;
    top: 50%;
    left:50%;
    z-index:5;
}
.progressbar .step:last-of-type .step-line{
    display:none;
}
deleted 29 characters in body
Source Link
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};
Source Link

JS Progress Bar Widget

Demo of the widget: http://jsfiddle.net/slicedtoad/Lywvbsf4/

It's a progress bar that shows a list of steps and which one is being completed as well as allowing previous steps to be revisited.

It will be used to display the user's form completion progress on a web app that favors a client side approach (forms are submitted to the server at the last step).

I'd like feedback specifically on the widget based approached I took. I had the goals:

  • simple interface
  • low coupling to the rest of the app
  • easy to extend the functionality (it should be easy to add more callbacks to handle new functionality, for example)
  • no code bloat from
    • legacy support (the app is only supported on FF and Chrome)
    • unnecessarily portability and safety (i.e. it needs to be safe in this app, not every app)

I ended up making a lot of fairly arbitrary decisions, which I would like critiqued.

Widget:

var progressBar = function(id,options){
    this.init(id,options);
};
progressBar.prototype.init = function(options){
    this.id = options.id; // ID of the div that will store the progress bar
    this.$node;
    this.steps = options.steps;
    this.current = 0; // current step
    this.previousClickedCallback = options.previousClicked;
    this.draw(); // populate $node
    $(this.id).append(this.$node); // append $node to the DOM
    this.$node.on("click",".step-finished .step-number",
                  $.proxy(this.previousClick,this));
    this.next();
};
progressBar.prototype.previousClick = function(e){
    this.previousClickedCallback($(e.target).html());
};
progressBar.prototype.draw = function(){
    this.$node = $("<ol class='progressbar container'></ol>");
    var html = "";
    for(var step in this.steps){
        html +=
            "<li class='step'>" +
                "<div class='step-number'>"+(parseInt(step)+1)+"</div>" +
                "<div class='step-line'></div>" +
                "<div class='step-label-wrap'>" +
                    "<label class='step-label'>"+this.steps[step]+"</label>" +
                "</div>" +
            "</li>";
    }
    this.$node.html(html);
};
progressBar.prototype.goToStep = function(step){
    console.log("gotostep: ",step);
    if(step>=1 && step<=this.steps.length+1){
        this.current = parseInt(step);
        
        // Reset progress bar status
        this.$node.find(".step-current").removeClass("step-current");
        this.$node.find(".step-finished").removeClass("step-finished");
        
        // Set current step
        this.$node.find(".step:nth-child("+this.current+")").addClass("step-current");
        // Set all previous steps to finished
        for(var i = step-1; i > 0; i--){
            this.$node.find(".step:nth-child("+i+")").addClass("step-finished");
        }
    }
};
progressBar.prototype.next = function(){
    if(this.current<this.steps.length+1){
        this.goToStep(this.current+1);
    }
};
progressBar.prototype.previous = function(){
    if(this.current>=2){
        this.goToStep(this.current-1);
    }
};

Example usage:

var goBack = function(step){
    //cache current form or whatever
    pbar.goToStep(step);
};

var pbar = new progressBar({
    id:"#ProgressBar",
    steps:["Date","Items","Preview","Details","Confirm"],
    previousClicked:function(step){goBack(step);}
});
$("#next").on("click",function(){pbar.next()});
$("#previous").on("click",function(){pbar.previous()});

CSS (minimal):

ol.progressbar {
    list-style-type: none;
    padding-left:0;
}
.progressbar.container {
    display: flex;
    align-items: flex-end;
    padding-top: 22px;
}
.progressbar .step {
    flex-grow:1;
    position:relative;
    text-align: center;
    z-index:1;
}
.progressbar .step-number {
    position:relative;
    z-index:10;
    width: 20px;
    height: 20px;
    border-radius: 10px;
    background-color:white;
    display:inline-block;
    text-align: center;
    line-height: 20px;
    border:1px solid;
}
.progressbar .step-finished .step-number:hover{
    background-color: lightblue;
    cursor: pointer;
}
.progressbar .step-finished .step-number{
    background-color: green;
}
.progressbar .step-current .step-number{
    background-color:lightblue;
}
.progressbar .step-label-wrap {
    position: absolute;
    width:100%;
    top: -22px;
}
.progressbar .step-label {
    padding: 0px 1px;
}
.progressbar .step-line {
    height: 2px;
    background-color: black;
    width:100%;
    position:absolute;
    top: 50%;
    left:50%;
    z-index:5;
}
.progressbar .step:last-of-type .step-line{
    display:none;
}