Fork me on GitHub

Utility plugins

modalBox.js

Modal window has become a very popular way of showing information in detail, and getting needed input while blocking the main application flow. There are large numbers of attractive plugin available over the internet with lot of options. But the question is do we need that all?

Fact is we only use 30 to 40 % of that plugin and for that 30 to 40 % we compromise to use a large size plugin. In internet world size matters a lot. Least the size of your page greater the loading speed.

So why not use a plugin which is much smaller and have options which we need the most. modalBox.js is a very light weight plugin packed with only most used features Its overall size is around 7.05 kb ( 2.7 kb minified).

Download

Examples

A simplest one

$('.modalBox').modalBox();
//or
$('.modalBox').modalBox('open');



Modal box with defined width and height

$('.modalBox').modalBox({
'width':'500px',
'height':'500px'
});



Modal box with defined top and left


$('.modalBox').modalBox({
'top':'100px',
'left':'100px'
});



Modal box with all close options enable

$('.modalBox').modalBox({
		iconImg:'images/x.png',
		iconClose:true,
		keyClose:true,
		bodyClose:true
});



Modal box with all and global close button

$('.modalBox').modalBox({
		iconImg:'images/x.png',
		keyClose:true,
		iconClose:true,
		bodyClose:true
});



Modal box with all callback functions

$('.modalBox').modalBox({
		onOpen:function(){
			alert('successfully open');
			},
		onClose:function(){
			alert('successfully close');
			}
});



Mutiple modal box functions

$('.modalBox').modalBox({
        width:300,
        height:300,
        top:100,
        left:100,
        iconImg:'images/x.png',
        iconClose:true,
});

$('.modalBox2').modalBox({
        width:300,
        height:300,
        top:100,
        left:500,
        iconImg:'images/x.png',
        iconClose:true,
});

Documentation

Options
Options Default Allowed Description
width 'auto' Width in any unit(px,%,em) Change the width of modal box. (Plugin will not do any calculation for width if defined.)
height 'auto' Height in any unit(px,%,em) Change the width of modal box. (Plugin will not do any calculation for height if defined.)
top 'auto' (50%) Top in any unit(px,%,em) Change the top position of modal box. (Plugin will not do any calculation for margin top if top is defined.)
left 'auto' (50%) Left in any unit(px,%,em) Change the left position of modal box. (Plugin will not do any calculation for margin left if left is defined.)
overlay true true,false Overlay the body if overlay is true.(have class iw-modalOverlay)
iconClose false true,false Show a close icon on top right corner to close modal box.
keyClose true true,false Activate closing of modal box by pressing esc key while modal box is open.
bodyClose true true,false Activate closing of modal box by clicking outside of modal box.
iconImg '' Image source Source of icon image to display. (have class iw-closeImg)

Callback functions
Function Description
onOpen This callback function will be fired just after modal box is successfully open.
onClose This callback function will be fired just after modal box is successfully close.

Methods
1. Plugin Method : Passed as first argument of plugin(If need to define).
ex: $('.modalBox').modalBox('close');

Method Description
open Method to open modal box. It is a default method ,so if no method is defined open will be called.
close Method to close modal box(hide the modal box). Remove all events and element associated with modal box(except modal box itself.)

2. Global Method:
ex: $.modalBox.close();

Method Description
close Close all currently opened modal box. Called by $.modalBox.close().

Concept

What we need for our plugin. ?

1. A method to open it.
2. A method to close it.
3. Some options to change the behavior of our plugin. (like modal size, modal position and overlay).

Lets start creating our plugin.

1. Setting structure of our plugin.

Remember of proper name-spacing of your plugin so that your plugin will not conflict with any other code.
Let's name our plugin as modalBox. I will append "iw-" to every class which i will use for my plugin.

Structure Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
;(function ($, window, document, undefined) {
    $.fn.modalBox = function (method, option) {
        if (methods[method]) {
            methods[method].call(this, option);
        } else if (typeof method === 'object' || !method) {
            //we will add a default method in the case no method is defined
            methods. /*Default mehthod*/
            .call(this, method);
        }
        return this;
    };
    //a object which will store our global method and defaults
    $.modalBox = {};

    /*default options
	accessable globaly so you can change default option for all modal box.
	example : $.modalBox.defaults.overlay=true; so now overlay will be default for all modal box
	*/
    $.modalBox.defaults = {

    }

    /* we will define three category of method 
   1. Global method : We will keep all method which are globally accessable to change 
   the state of modal box (either all or one) which can be invoked from outside of plugin.
   
   2. Internal method : Methods which are used internally by plugin.
   
   3. Plugin method: Methods which can be accessed by passing name in the first parameter of plugin .*/

    //global methods 


    //internal method


    //plugin method
    var methods = {

    }
})(jQuery, window, document);

You would also like to see Plugin Authoring and Common plugin pattern

2. Implementing open method

  • We will create a plugin method to open our modal box.
  • We will give some configuration option to change its default behavior.
  • We will also give option of overlaying the document.

The logic in our open method is so simple,

  • If no size and position property is defined we will show it on center of the window.
  • If modal size is more than window size reduce it to window size.
  • First apply width and height to box so we can get exact size of modal box in pixel.
  • We will follow a very common way to center our modal box. Give left and top 50% and margin left and top equals to half of width and height
  • If left and top is defined use it and give no margin.
  • We also need to define function to add overlay.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
// open method along with some basic configuring options
;(function ($, window, document, undefined) {
    $.fn.modalBox = function (method, option) {
        if (methods[method]) {
            methods[method].call(this, option);
        } else if (typeof method === 'object' || !method) {
            //we will make open as our defaul method
            methods.open.call(this, method);
        }
        return this;
    };
    $.modalBox = {};

    //default options

    $.modalBox.defaults = {
        //all properties will  with unit like 10px or 10%
        width: 'auto',
        height: 'auto',
        left: 'auto',
        top: 'auto',
        overlay: true
    }

    //global methods

    //internal methods
    // add overlay
    function addOverlay() {
        $('body').append('<div class="iw-modalOverlay"></div>');
        $('.iw-modalOverlay').css({
            display: 'block',
            width: '100%',
            height: '100%',
            position: 'fixed',
            top: 0,
            left: 0,
            display: 'block',
            'z-index': '1000'

        });
    }

    //plugin methods
    var methods = {
        /* open method. 	*/
        open: function (option) {
            option = $.extend({}, $.modalBox.defaults, option);
            // $.extend will merge passed options with defalut option . 

            var elm = this,
                //to calculate width and height of modal box
                elmWidth = elm.width(),
                elmHeight = elm.height(),
                elmWidthO = elm.outerWidth(),
                elmHeightO = elm.outerHeight(),
                windowWidth = $(window).width(),
                windowHeight = $(window).height(),
                width = option.width != 'auto' ? option.width : Math.min(elmWidthO, windowWidth) - (elmWidthO - elmWidth),
                height = option.height != 'auto' ? option.height : Math.min(elmHeightO, windowHeight) - (elmHeightO - elmHeight);

            //store its original width to element data so later we can regain its original size
            elm.data('iw-size', {
                'width': elmWidth,
                'height': elmHeight
            })
            //to add modalBox class
            .addClass('iw-modalBox')
            //apply new size
            .css({
                width: width,
                height: height,
                position: 'fixed',
            });
        });


    //to calculate left and top and margin
    var top = '50%',
        left = '50%',
        marginLeft = elm.width() / 2,
        marginTop = elm.height() / 2;

    if (option.left != 'auto') {
        left = option.left;
        marginLeft = '0';
    }
    if (option.top != 'auto') {
        top = option.top;
        marginTop = '0'
    }

    elm.css({
        top: top,
        left: left,
        'margin-left': -marginLeft,
        'margin-top': -marginTop,
        'display': 'block',
        'z-index': '99999'
    });

    //if overlay is true add overlay.
    if (option.overlay) {
        addOverlay();
    }

}
}
})(jQuery, window, document);

3. Implementing close method.

For a better user experience we need to give different way to close our modal box. Even though we will give all as option so user can choose what he need among them. Remember it is a best practice to namespace your events so it can be easily unbind and trigger later.
  • A close button on the top right corner.
    • For this we need two options, flag  (default to false) to show image and other src of image .
    • Image can be only shown when modal box is less than window height. (we will condition for max width and height of modal box is 50 px less window height assuming images max size will be 50 px).
  • By click on outside of modal box.
    • We need to add on flag as option which will define weather clicking outside of modal box we need to close it or not. (default to true).
    • We will create overlay with no background, if  overlay is set to false and we will add close event on overlay instead on body to escape from bubbling of event to body.
  • Key event to close(Esc key)
    • We will also give a close event on esc key press with a flag to activate/deactivate it (default to true).
  • Close method (globally accessible) .
    • We will add a close method which will close all modal box open at a time.

  • **We will keep all event handler in internal method.

This all method will call plugin close method which you can call for a particular modal box.  

On close we need to

  • Unbind all event bound to html and window.
  • Remove overlay if present.
  • Hide modal box.
  • Remove close image if present.

4. Implementing callback function :

Callback functions are the most important part of a plugin as they give you access in the middle of execution of plugin.
We will define two callback functions in for our two main methods (open , close)
1. onOpen : Which is called when a modal box opened.  
2. onClose : Which is called when modal box is successfully closed.

*Inside a callback function this will point to selector jquery object.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
;(function ($, window, document, undefined) {
    $.fn.modalBox = function (method, option) {

        if (methods[method]) {
            methods[method].call(this, option);
        } else if (typeof method === 'object' || !method) {
            methods.open.call(this, method);
        }
        return this;
    };
    $.modalBox = {};

    //default options

    $.modalBox.defaults = {
        //all properties with unit like 10px
        width: 'auto',
        height: 'auto',
        left: 'auto',
        top: 'auto',
        overlay: true,
        iconClose: false,
        keyClose: true,
        bodyClose: true,
        iconImg: 'image/closeIcon.png',

        //callback function
        onOpen: function () {},
        onClose: function () {},
    }

    //global methods

    //to close all modal box
    $.modalBox.close = function () {
        $('.iw-modalBox').each(function () {
            methods['close'].call($(this));
        });

    }


    //internal method
    var keyEvent = function (e) {
        var keyCode = e.keyCode;
        //check for esc key is pressed.
        if (keyCode == 27) {
            $.modalBox.close();
        }
    };
    var clickEvent = function (e) {
        //check if modalbox is defined in data
        if (e.data) {
            methods['close'].call(e.data.modalBox);
        } else {
            $.modalBox.close();
        }
    };
    var resizeEvent = function (e) {
        var img = e.data.img,
            elm = e.data.elm;
        img.css({
            top: (elm.offset().top - $(window).scrollTop() - 8) + 'px',
            left: (elm.offset().left - $(window).scrollLeft() + elm.width() - 8) + 'px',
            position: 'fixed',
            'z-index': '99999'
        });
    }
    //to show overlay
    var addOverlay = function () {
        $('body').append('<div class="iw-modalOverlay"></div>');
        $('.iw-modalOverlay').css({
            display: 'block',
            width: '100%',
            height: '100%',
            position: 'fixed',
            top: 0,
            left: 0,
            display: 'block',
            'z-index': '1000'

        });
    }

    var methods = {
        open: function (option) {
            option = $.extend({}, $.modalBox.defaults, option);

            var elm = this,
                elmWidth = elm.width(),
                elmHeight = elm.height(),
                elmWidthO = elm.outerWidth(),
                elmHeightO = elm.outerHeight(),
                windowWidth = $(window).width(),
                windowHeight = $(window).height(),
                width = option.width != 'auto' ? option.width : Math.min(elmWidthO, windowWidth) - (elmWidthO - elmWidth),
                height = option.height != 'auto' ? option.height : Math.min(elmHeightO, windowHeight) - (elmHeightO - elmHeight);

            //to add modalBox class
            elm.data('iw-size', {
                'width': elmWidth,
                'height': elmHeight
            })
                .addClass('iw-modalBox')
                .css({
                width: width,
                height: height,
                position: 'fixed',
            });


            var top = '50%',
                left = '50%',
                marginLeft = elm.outerWidth() / 2,
                marginTop = elm.outerHeight() / 2;

            if (option.left != 'auto') {
                left = option.left;
                marginLeft = '0';
            }
            if (option.top != 'auto') {
                top = option.top;
                marginTop = '0'
            }

            elm.css({
                top: top,
                left: left,
                'margin-left': -marginLeft,
                'margin-top': -marginTop,
                'display': 'block',
                'z-index': '99999'
            });

            if (option.overlay) {
                addOverlay();
            }

            //to bind close event	
            if (option.iconClose) {
                if ((elm.outerWidth() < (windowWidth - 50)) && (elm.outerHeight() < (windowHeight - 50))) {
                    var randId = Math.ceil(Math.random() * 1000) + 'close';
                    var img = $('<img src="' + option.iconImg + '" class="iw-closeImg" id="' + randId + '"/>');
                    elm.attr('closeImg', randId);
                    img.bind('click', {
                        modalBox: elm
                    }, clickEvent);
                    //we will add resize event to retain the correct position of close button.
                    $(window).bind('resize.iw-modalBox', {
                        img: img,
                        elm: elm
                    }, resizeEvent);
                    $(window).triggerHandler('resize.iw-modalBox');
                    $('body').append(img);
                }
            }

            if (option.keyClose) {
                $('html').bind('keyup.iw-modalBox', keyEvent);
            }

            if (option.bodyClose) {
                /*create a overlay(or use existing) in which we will give close event to overlay 
						and not in the body to come out of bubbling issue */
                var overlay = $('.iw-modalOverlay');
                if (overlay.length == 0) {
                    addOverlay();
                    overlay = $('.iw-modalOverlay');
                    overlay.css({
                        'background': 'none'
                    });
                }
                overlay.bind('click', clickEvent);
            }
            //call callback function
            option.onOpen.call(this);
            elm.data('closeFun', option.onClose)

        },
        close: function () {
            var elm = this;
            if (elm.data('iw-size')) {
                //close modal and unbind all event associated with it.
                $('.iw-modalOverlay').remove()
                $('html').unbind('keyup.iw-modalBox');
                $(window).unbind('resize.iw-modalBox');
                var imgId = elm.attr('closeImg');
                if (imgId) {
                    elm.removeAttr('closeImg');
                    $('#' + imgId).remove();
                }
                elm.css({
                    'display': 'none',
                    'width': elm.data('iw-size').width,
                    'height': elm.data('iw-size').height
                })
                //call callback function
                elm.data('closeFun').call(this);

                //restore modal box
                elm.removeData('iw-size')
                    .removeData('closeFun')
                //remove class
                .removeClass('iw-modalBox');
            }

        }
    }
})(jQuery, window, document);


5. Adding CSS to modal box

We have three classes related to modal box.
  1. iw-modalBox for modal box.
  2. iw-modalOverlay for overlay.
  3. iw-closeImg for close icon.

For basic we just need to give css on overlay
1
2
3
4
.iw - modalOverlay {
    background: #000;
    opacity:.8;
}

Using our plugin is quite simple. Lets see some example.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
	//easist way to open modal box
	$('.modalBox').modalBox();

	//calling modalBox with overided size and width options 

	$('.modalBox').modalBox({
	    width: '400px',
	    height: '400px',
	    top: '20%',
	    left: '20%',
	});

	//calling modalBox with overided close and overlay options 
	$('.modalBox').modalBox({
	    overlay: true,
	    iconImg: 'images/basic/x.png',
	    keyClose: true,
	    iconClose: true,
	    bodyClose: true,
	});

	//calling with callback function and all other options
	$('.modalBox').modalBox({
	    width: '400px',
	    height: '400px',
	    top: '20%',
	    left: '20%',
	    overlay: true,
	    iconImg: 'images/basic/x.png',
	    keyClose: true,
	    iconClose: true,
	    bodyClose: true,
	    onOpen: function () {
	        alert('successfully open' + JSON.stringify(this));
	    },
	    onClose: function () {
	        alert('successfully close' + JSON.stringify(this));
	    }
	});
Close All       Close this
This documentaion is moved to http://ignitersworld.com/lab/modalBox.html. It will be no longer maintained here .