Saturday, January 17, 2009

Thursday, January 15, 2009

Monday, January 12, 2009

Modal Dialogue - Based on Mootools and Clientcide script

Modal dialogue is one of the very commonly used dialogue on web these days. It is a special dialogue box that sits above all html elements on the screen. Nowadays the regular DHTML dialogue is combined with modal overlay - overlay that fills the screen with very high z-index and does not allow access to underlying UI elements. It is very cool to see a window turn light gray and a dialogue appearing center to the screen above this overlay. It is the current trend.

There are numerous script available to accomplish this. Clientcide is one among those.

Many times I wanted to center a html fragment- usually a div appear as overlay centered to the browser window, stay in center if they scroll the browser and stay in center if they resize the window as well and be a modal window...

I wanted to club both of the above feature ... basically a centered modal dialogue box above a grayed out background.

So, let us say, we have a div that hold some UI element - may be just an image or could be bunch of input fields. You want to make that DIV appear in the middle of the screen as modal dialogue combined with grayed out overlay. Here's is the simple script that will help you accomplish that:

Dependencies:

I wrote a wrapper functions to achieve the above requirement.

Below is my source code:

//Helper class to center element in current window, show element etc
var WindowHelper = {
defaultOptions: {
onError: $empty, animate: true
},
defaultStyle: {
position: 'fixed', 'z-index': 5100
},
_minOf: function(x, y) { // Utility function to find min of 2 numbers
if (($type(x) != 'number') || ($type(y) != 'number')) {
return -1;
}
if (x > y) {
return y;
}
return x;
},
_maxOf: function(x, y) { // Utility function to find max of 2 numbers
if (($type(x) != 'number') || ($type(y) != 'number')) {
return -1;
}
if (x < y) {
return y;
}
return x;
},
centerWindow: function(element, options) {
if (element) {
var top = window.getSize().y / 2;
var left = window.getSize().x / 2;
var opts = $merge(this.defaultOptions, options);

element.setStyle("display", "block"); //Without this below line does not give correct value.
top = this._maxOf(top - (element.getSize().y / 2), 0);
left = this._maxOf(left - (element.getSize().x / 2), 0);

element.setStyle("top", top);
element.setStyle("left", left);
element.setStyles(this.defaultStyle);

if (Browser.Engine.trident4) element.setStyle('position', 'absolute');

return true;
}
},
showElement: function(element, options) {
element.setStyle("visibility", "hidden");
element.setStyle("opacity", 0);
element.setStyle("display", "block");

if (options && options.animate) {
var myTween =
new Fx.Morph(element,
{
duration: 1000
, onComplete: this._showComplete(element)
});
myTween.start({ 'opacity': [0, 1] });
} else {
element.setStyle("opacity", 1);
}
},
_showComplete: function(element) {
element.setStyle('display', 'block');
element.setStyle('visibility', 'visible');
},
_closeComplete: function(element, options) {
element.setStyle('display', 'none');
if ($type(options.onWindowClose) == "function") {
options.onWindowClose();
}
},
close: function(element, options) {
if (element) {
if (options && options.animate) {
var myTween =
new Fx.Morph(element,
{
duration: 300
, onComplete: this._closeComplete(element, options)
});
myTween.start({ 'opacity': [.5, 0] });
} else {
this._closeComplete(element, options);
}
}
}
};

var CTModalizer = {
modalInstance: this.modalInstance || new Modalizer(),
defaultOpts: {
opacity: '0.5'
, hideOnClick: false
, 'z-index': 5000
, onPreGrab: $empty
, animate: true
, onWindowClose: $empty
, updateOnResize: true
},
init: function(elementIdToGrab, options) {
var opts = $merge(this.defaultOpts, options);

$$('.close').each(function(el) {
el.removeEvents("click");
});

$$('.close').each(function(el) {

el.addEvent("click", function() {
this.closeGrabbedWindow(elementIdToGrab);
} .bind(this));
}, this);

var grabEl = $(elementIdToGrab);
if (opts.updateOnResize) {
window.addEvent("resize", this._resize(grabEl, opts));
}
},
_resize: function(grabEl, opts) {
WindowHelper.centerWindow(grabEl, opts);
},
grab: function(elementIdToGrab, options) {
var grabEl = $(elementIdToGrab);
this.init(elementIdToGrab, options);
if (WindowHelper.centerWindow(grabEl, options)) {
var opts = $merge(this.defaultOpts, options);
WindowHelper.showElement(grabEl, opts);
this.modalInstance.modalShow(opts);
if ($type(opts.OnPreGrab) == "function") {
opts.OnPreGrab();
}
}
},
closeGrabbedWindow: function(grabbedElementId) {
var el = $(grabbedElementId);
el.setStyle("z-index", "4100");
WindowHelper.close(el, this.modalInstance.modalOptions);
this.modalInstance.modalHide();
}
};



Usage:

<script type="text/javascript" language="javascript">
var options = {
modalStyle: { opacity: 0.2 }
, animate: true
, onWindowClose: this.CloseRemovePopup };

function showPopUp(grabElementId) {
CTModalizer.grab(
grabElementId
, options);

}

function CloseRemovePopup() {
alert('Window closed');
}
</script>


Sample HTML:

<div id="ModalPopUp1" class="PopupContainer" style="width: 560px; height: 150px;">
Sample text <div class="close"><u>Close</u></div>
</div>

<input type="button" value="Show pop up" onclick="javascript:{ showPopUp('ModalPopUp1'); }" />

Not the class="close" - I use this class to identify the element to which I associate the close event.

Feel free to modify the scripts in case you need to .. :)