23 January 2011

IE window.createPopup() - cross browser solution

Hello,

Probably a lot of you came to the situation when you needed to have a popup as the one which IE is providing when using window.createPopup().

I have surfed a lot on the internet, but I couldn't find a solution that would satisfy my requirements. This is why I decided to create my own library in Javascript. I will provide the code of it below in this post.

Note: jQuery is used in this code, this is why you will need first of all to include jQuery library (Core & UI) before below code.


The code:
--------------------------------
var popupInstance = null;

function createCrossBrowserPopup(){
    return new _popup();
}

function _popup() {
    this.wnd = null;
    this.hiddenFrame = null//workaround for IE 6 - with divs and select (divs are appearing behind select elements)
    this.showHiddenFrame = showHiddenFrame;
    this.displayPopupContainer = displayPopupContainer;
    this.html = "";
    this.setHTML = _setHTML;
    this.show = _show;
    this.hide = _hide;
    this.triggerElementId = null;
    this.blur = null;
}

function _setHTML(html, event) {
    this.html = html;
    if (this.wnd != null) {
        this.wnd.html(this.html);
    }

    if (event != null)
        stopEventPropagation(event, null);
}

/// leftOffset: the left offset of the popup
/// topOffset: the top offset of the popup
/// width: the width of the popup
/// height: the height of the popup
/// element: the element which causes the popup to be opened
/// event: the event which cased the popup to be opened
function _show(leftOffset, topOffset, width, height, element, event) {

         // Hide previous popup if existed
    if (popupInstance != null && element.id != popupInstance.triggerElementId) {
        popupInstance.hide();
        return;
    }

    // if popupInstance != null this means that the same popup was called, makes no sense to create it again
    if (popupInstance == null){
        leftOffset = leftOffset != null ? leftOffset : 0;
        topOffset = topOffset != null ? topOffset : 0;

        this.displayPopupContainer(element, width, height, leftOffset, topOffset);

        //workaround for IE 6 - with divs and select (divs are appearing behind select elements)
        this.showHiddenFrame(element, width, height, leftOffset, topOffset);
        // end of workaround

        setElementsPosition(element, leftOffset, topOffset);

        // save the id, onblur event of the element that fires the popup
        // and also save the instance of this object - for $(document).click and $(window).resize
        this.triggerElementId = element.id;
        this.blur = element.onblur;
        element.onblur = null;
        popupInstance = this;
    }

    stopEventPropagation(event);
}

function _hide() {
    $(".modal_popup_container").hide();
    if (this.triggerElementId != null) {
        // Assign back the blur event (using simple Javascript, not jQuery as it is causing onblur to be fired 2 times) and reset some variables
        $('#' + this.triggerElementId)[0].onblur = this.blur;
        if ($.isFunction(this.blur)) {
            $('#' + this.triggerElementId)[0].onblur();
        }
        else
        if(typeof(this.blur) == 'string')
        {
            var regex = new RegExp('(?=[\w.])this(?!\w)/g');
            eval(this.blur.replace(regex, '$(\'#' + this.triggerElementId + '\')[0]'));
        }

        // reset variables
        this.triggerElementId = null;
        this.blur = null;
        popupInstance = null;
    }
}

function displayPopupContainer(element, width, height, leftOffset, topOffset) {
    if (this.wnd == null) {
        this.wnd = $('<div />');
        this.wnd.addClass('modal_popup_container');
        this.wnd.css({
                'position' : 'absolute',
                'z-index' : '999',
                'margin' : '0'});
    }

    this.wnd.css({ 'width': width, 'height': height });
    this.wnd.html(this.html);
    this.wnd.show();

    var parentElement = $(element).parent();
    $(parentElement).append(this.wnd);
}

function showHiddenFrame(element, width, height, leftOffset, topOffset) {
    if (this.hiddenFrame == null) {
        this.hiddenFrame = $('<iframe />');
        this.hiddenFrame.addClass('modal_popup_container');

        this.hiddenFrame.attr({
            "src""javascript:'&lt;html&gt;&lt;/html&gt;';",
            "scrolling""no",
            "frameborder": 0
        });
        this.hiddenFrame.css({
            "position""absolute",
            "border""none",
            "display""block",
            "z-index""998",
            "margin""0"
        });
    }

    this.hiddenFrame.css({ "width": width, "height": height });
    this.hiddenFrame.show();

    var parentElement = $(element).parent();
    $(parentElement).append(this.hiddenFrame);
}

function setElementsPosition(element, leftOffset, topOffset) {
    $(".modal_popup_container").position({
        my: "left top",
        at: "left bottom",
        of: $(element),
        offset: leftOffset + " " + topOffset,
        collision: "fit"
    });
}

function stopEventPropagation(event)
{
    // manage FireFox and IE events, check if event was passed, else try and get window.event
    var e = (!event) ? window.event : event;
    // avoid that the current click event propagates up
    if (typeof (e) != "undefined") {
        if (e.stopPropagation)
            e.stopPropagation();
        else e.cancelBubble = true;
    }
}

// hide the popup when user clicks outside it
$(document).click(
    function(event) {
        if ($(event.target).closest('.modal_popup_container').get(0) == null
        && popupInstance != null) {
            popupInstance.hide();
        }
    });

$(window).resize(
    function(event) {
        if (popupInstance != null) {
            popupInstance.hide();
        }
    });
--------------------------------

Bowser Support



The above code should work in IE 6/7/8, Chrome, Safari and Firefox.

Code explained:
Well, first of all when calling createCrossBrowserPopup()we create an instance of the _popup() object.
And just after that we can use that object.

What you need to do first of all, before displaying the popup, you should provide a html to display it.

To show the popup you need to call popup.show with corresponding parameters.

When show is called then all popups on the window are hidden. Then a div is appended to the parent element. This div will contain the html that you have provided earlier.

As probably most of you know - there is a problem with divs in IE 6 and the problem actually is that dropdown elements are displaying on top of our div element. : ( - Not good. So in order to fix this I have decided to create an iframe and show it behind our div - see z-index numbers. This way our popup will work on IE 6 too.

Next, I save the element id of the element which has triggered the popup as well as save the onblur event content, so that when the popup disappears I can trigger the onblur event of the element. Then I clear the onblur event of the element so that it is not triggered when my popup get's the focus.

As this object is intended to be a generic one I need to save the instance of an object in a global variable: popupInstance, I save it because I need it when the window is resized, or a click outside of the
popup is made, I need it to hide my popup.

Then I stop event propagation. So that the click event does not propagate further. How to use: Here is an example of how you could use the component. This will show a popup (width: 100px, height: 50px , with an leftOffset of 25px) when the user clicks the input.

<scriptlanguage="javascript" type="text/javascript">
...
 var popup = createCrossBrowserPopup();
 popup.setHTML("<div style='width:100%; height:100%;
background-color:#AAFFEE;border-width: 2px; border-color: silver; border-style:
solid;' onclick='changePopupHTML();'> test </div>"
, null);

function changePopupHTML() {
    popup.setHTML("<div style='width:100%; height:100%; background-color:#AA11EE;border-width: 2px; border-color: silver; border-style: solid;'> test222 </div>", null);
}
...

</script>
...

<input type="text" id="txtExample" onclick="popup.show(25, 0, 100, 50, this, event);" />


Conclusion, Notes and Others:
I know that this could be achieved easier(using javascript functions when setting the html of the popup or using jQuery plugins) but the initial propose of this object was to correspond to the window.createPopup() from IE.

I will probably create a better version, or even create a jQuery plugin in the future, if required, so if you need that, then tell me and I will find some time to help you.

I have lost a lot of time for doing all this, and this is why I am posting this. I was disappointed when I figured out that there is no cross browser solution for window.createPopup() on the internet.

Note: this popup will also work on AJAX MoldaPopupExtender, This code is not probably best written, so I will accept/wait any suggestions for improvement!!!

HERE is a link with an EXAMPLE


In case you have any questions let me know - write a comment on my blog.

16 comments:

user521180 said...

Hi. I get javascript error "popup undefined" any idea why? here is how my code looks http://jsfiddle.net/aDFSR/

any ideas?

user521180 said...

Hi again. Ignore my first comment, I got it working. its a nice replacement however it does not behave exactly as window.createpopup. it can not pop out of its frame like window.createpopup does. so using it as a drop down menu that would drop down from one frame or iframe and overlap the other does not work

Roman Gherman said...

Hi,
Yes it is not possible to achieve this by Javascript.

window.createPopup() can pop out of its frame because it's an IE function, done by IE.

andry yudha said...

hi,,

i can't active my javascript on my blog,,
can you help me?

Roman Gherman said...

Hi andry yudha,

What do you mean?

Regards,
Roman

Anonymous said...

Very Good Info regarding CreatePopup... keep posted if u find something new on this..all the best

Babita Bhatt said...

I wanted to use pop.show(..) inside function test(event) and call this function in onClick but this doesn't work, I don't reason why this is not working like that. can you please help? this is very urgent, would appreciate timely help.

Roman Gherman said...

Babita,
I have sent you an email with an example.
Regards,
Roman

Babita Bhatt said...

Thanks Roman, the solution worked for IE but unfortunately I didn’t work for IE.
Roman I have one more concern, I don’t have event in my function as its executing from server side so I need to add the event forcefully so I used addEventListener like this
document.addEventListener("mousemove", function(e){test(this, e)}, false);
but this is not working please help. I have emailed you the test file.

Thanks a ton again.

Regards
Babita

Babita Bhatt said...

Correcting the previous comments, it worked in FireFox but not in IE.

Roman I am waiting to hear from you, please let me know why my function is not working when I call it from

document.addEventListener("mousemove", function(e){test(this, e)}, false);

I have sent you the test file, please help me.

Anonymous said...

I can't get this working in IE8 or Firefox, it works in Chrome and Safari, are there any updates to this?

Roman Gherman said...

Hi, there are no updates for it. However it should work on IE8 and Firefox as it was tested.
DO you get any errors?

Manjula said...

Hi,

I can't get this working in IE10, chrome & Firefox. I also have same Situation as Babita Bhatt's like i have onCLick="FuncA()" and inside "FuncA()" i want to call this popup.show to show the custom date control popup.

are there any updates to this? please help

Anonymous said...

Since window.createPopup() is deprecated in IE11, does your solution mentioned in this blog post replace createPopup for IE11?

Roman Gherman said...

I have never tried it.

Anonymous said...

Will this work cross frame. A benefit of .createPopup() was that you could lay your menu (or what have you) into a window that was presented in front of other elements. So, aside from the IE6 issue explained above, will this cross-browser solution work across frames in a frameset (not iframes)...so for example, if I click on a button in one frame...the popup window appears...and if it is big enough it overlays any surrounding frames. This is the single biggest benefit of having the .createPopup().

Post a Comment

your thoughts are welcome:

Need more? Leave comments and subscribe to my blog.

.