Skip to content

Instantly share code, notes, and snippets.

@cecilemuller
Last active May 12, 2019 15:29
Show Gist options
  • Save cecilemuller/6147729 to your computer and use it in GitHub Desktop.
Save cecilemuller/6147729 to your computer and use it in GitHub Desktop.
Dynamically-generated (and optionally multi-steps) modals for Bootstrap 2.3.2
(function() {
"use strict";
/**
* @namespace
*/
var BOOTSTRAP = {};
/**
* Event types that `BOOTSTRAP.Modal.events` might send.
* @readonly
* @enum {string}
* @property {string} MODAL_SHOW - This event fires immediately when the show instance method is called.
* @property {string} MODAL_SHOWN - This event is fired when the modal has been made visible to the user (will wait for css transitions to complete).
* @property {string} MODAL_HIDE - This event is fired immediately when the hide instance method has been called.
* @property {string} MODAL_HIDDEN - This event is fired when the modal has finished being hidden from the user (will wait for css transitions to complete).
* @property {string} MODAL_CONFIRM - This event fires when the modal is closed using the primary button.
*/
BOOTSTRAP.EVENTS = {
MODAL_SHOW: 'show',
MODAL_SHOWN: 'shown',
MODAL_HIDE: 'hide',
MODAL_HIDDEN: 'hidden',
MODAL_CONFIRM: 'BOOTSTRAP.EVENTS.MODAL_CONFIRM'
};
/**
* Dynamically-created modal window.
* @class
* @member {String} title - Text shown in the header of the modal.
* @member {String} body - Text shown in the body of the modal.
* @member {Array} steps - Defines the steps of a multistep modal.
* @member {string} status - Muted status text.
* @member {string} submit - Label of the primary button.
* @member {string} cancel - Label of the cancel button.
* @member {string} events - jQuery reference to the container.
* @constructor
*/
BOOTSTRAP.Modal = function(data){
if (typeof data === 'undefined') data = {};
this.title = (typeof data.title === 'undefined') ? false : data.title;
this.body = (typeof data.body === 'undefined') ? false : data.body;
this.step_ids = [];
this.steps = (typeof data.steps === 'undefined') ? false : data.steps;
this.status = (typeof data.status === 'undefined') ? false : data.status;
this.submit = (typeof data.submit === 'undefined') ? false : data.submit;
this.cancel = (typeof data.cancel === 'undefined') ? false : data.cancel;
var html = '<div class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">';
if (this.title || this.cancel){
html += '<div class="modal-header">';
if (this.cancel) html += '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>';
if (this.title) html += '<h3>' + this.title + '</h3>';
html += '</div>';
}
html += '<div class="modal-body">';
if (this.body) html += '<p>' + this.body + '</p>';
if (this.steps){
var step_ids = [];
var l = this.steps.length;
html += '<ol>';
for (var i = 0; i < l; i++){
var step = this.steps[i];
html += '<li class="muted">';
if (step.title) html += '<p>' + step.title + '</p>';
if (step.percents || (step.percents === 0)) html += '<div class="progress progress-striped ' + (step.percents > 0 ? '' : 'hidden') + '"><div class="bar" style="width: ' + Math.max(0.5, step.percents) + '%;"></div></div>';
html += '</li>';
step_ids.push(step.id);
}
html += '</ol>';
this.step_ids = step_ids;
}
html += '</div>';
if (this.status){
html += '<div class="modal-footer modal-status muted"><p>' + this.status + '</p></div>';
}
if (this.submit || this.cancel){
html += '<div class="modal-footer">';
if (this.cancel) html += '<button class="btn" data-dismiss="modal" aria-hidden="true">' + this.cancel + '</button>';
if (this.submit) html += '<button class="btn btn-primary btn-submit">' + this.submit + '</button>';
html += '</div>';
}
html += '</div>';
var options = {"show": false};
if (this.close){
options.keyboard = true;
} else {
options.keyboard = false;
options.backdrop = 'static';
}
var $container = $(html);
if (this.submit){
$container.find('.btn-submit').on('click', $.proxy(function(){
this.events.trigger(BOOTSTRAP.EVENTS.MODAL_CONFIRM);
this.hide();
}, this));
}
$container.modal(options);
this.events = $container.appendTo('body');
this.$li = false;
this.$progress = false;
this.$bar = false;
};
/**
* Changes the status text shown in the footer.
* @param {String} text - Text to display
*/
BOOTSTRAP.Modal.prototype.updateStatus = function(text){
if (text === false){
this.events.find('.modal-status').remove();
} else if (this.status === false){
this.events.find('.modal-body').after('<div class="modal-footer modal-status muted"><p>' + text + '</p></div>');
} else {
this.events.find('.modal-status p').html(text);
}
this.status = text;
};
/**
* Opens the modal.
*/
BOOTSTRAP.Modal.prototype.show = function(){
this.events.modal('show');
};
/**
* Closes the modal.
*/
BOOTSTRAP.Modal.prototype.hide = function(){
this.events.modal('hide');
};
/**
* Opens the modal if it's closed, closes it if it's open.
*/
BOOTSTRAP.Modal.prototype.toggle = function(){
this.events.modal('toggle');
};
/**
* Sets the active step (multistep modals only).
* @param {String} step_id - Unique identifier of the step
*/
BOOTSTRAP.Modal.prototype.startStep = function(step_id){
var index = this.step_ids.indexOf(step_id);
if (index > -1){
this.$li = this.events.find('li:nth-of-type(' + (index + 1) + ')').removeClass('muted').addClass('text-info');
this.$progress = this.$li.find('.progress').fadeIn('slow').addClass('active').removeClass('hidden');
this.$bar = this.$li.find('.bar');
return true;
} else {
return false;
}
};
/**
* Changes the percentage of the current step (multistep modals only).
* @param {Number} percents - Width of the colored part of the progress bar of the current step, if it has one.
*/
BOOTSTRAP.Modal.prototype.updateStep = function(percents){
if (this.$bar){
this.$bar.css('width', percents + '%');
return true;
} else {
return false;
}
};
/**
* Sets the current step as failed (multistep modals only).
* @param {String} text - Text to display
*/
BOOTSTRAP.Modal.prototype.failStep = function(text){
if (this.$li){
this.$li.removeClass('text-info').addClass('text-error');
this.$progress.remove();
this.$li.append('<div class="alert alert-error">' + text + '</div>');
this.$li = this.$bar = this.$progress = false;
return true;
} else {
return false;
}
};
/**
* Sets the current step as successfully completed (multistep modals only).
*/
BOOTSTRAP.Modal.prototype.completeStep = function(){
if (this.$li){
this.$li.removeClass('text-info').addClass('text-success');
this.$bar.css('width', '100%').addClass('bar-success');
this.$progress.removeClass('active');
this.$li = this.$bar = this.$progress = false;
return true;
} else {
return false;
}
};
window['BOOTSTRAP'] = BOOTSTRAP;
})();
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet"/>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="classes.bootstrap.js"></script>
<script>
jQuery(function(){
"use strict";
var mymodal = new BOOTSTRAP.Modal({
"title": 'sudo make me a cake',
"steps": [
{
"id": 'wake_up',
"title": 'Wake up and get out of bed'
},
{
"id": 'milk',
"title": 'Get milk from the store',
"percents": 0
},
{
"id": 'bake',
"title": 'Bake a cake',
"percents": 0
}
]
});
mymodal.show();
mymodal.startStep('wake_up');
mymodal.completeStep();
mymodal.startStep('milk');
mymodal.updateStatus('All ingredients acquired');
mymodal.completeStep();
mymodal.startStep('bake');
mymodal.updateStep(30);
mymodal.failStep('Kitten splilled the milk');
});
</script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet"/>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="classes.bootstrap.js"></script>
<script>
jQuery(function(){
"use strict";
var mymodal = new BOOTSTRAP.Modal({
"title": 'Would you like some cake?',
"body": 'Cake is a form of bread or bread-like food. In its modern forms, it is typically a sweet baked dessert. In its oldest forms, cakes were normally fried breads or cheesecakes, and normally had a disk shape. Determining whether a given food should be classified as bread, cake, or pastry can be difficult (https://en.wikipedia.org/wiki/Cake).',
"submit": 'Yes please',
"cancel": 'No thanks'
});
mymodal.events.on(
BOOTSTRAP.EVENTS.MODAL_SHOWN,
function(){
console.log('The modal is opening');
}
);
mymodal.events.on(
BOOTSTRAP.EVENTS.MODAL_HIDDEN,
function(){
console.log('The modal is closing');
}
);
mymodal.events.on(
BOOTSTRAP.EVENTS.MODAL_CONFIRM,
function(){
console.log('The user confirmed');
}
);
mymodal.show();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment