mpen
mpen

Reputation: 282825

showModalDialog alternative?

I'm managing an old site that's riddled with popup windows. They're quite annoying because they keep getting lost behind the main window. I'm slowly moving them over to over to a modern 'lightbox' but it's a slow and tedious process because all these popups contain forms and the validation is done server-side, which means I need to be able to submit the form and then re-render it if there's an error without breaking the whole page.

I just discovered there's a window.showDialogBox which works perfectly in Firefox (prevents you from clicking the main page until you close the dialog), but Chrome has already deprecated it, and IE only half supports it.

So, is there anything I can replace window.open with in the mean time to provide a better user experience, without re-writing every form to send and receive JSON via XHR?

Upvotes: 14

Views: 45422

Answers (4)

Saira Asghar
Saira Asghar

Reputation: 11

you can check this link for jQuery Modal, to use this code, you need to include jquery-ui javascript and css files

Upvotes: 0

Axel Amthor
Axel Amthor

Reputation: 11096

here's my code:

/**
 * May 2015: showModalDialog will not be supported any longer, so, if not available, we need to make a pure
 * window.open and a catch which callbacks.
 * 
 * In contradiction to other solutions, this "emulator" is capable of loading 
 * cross-origin urls such as oAuth2 redirect cascades, which can not be put in to iframes or dialogs due to
 * their CSSP settings!
 * 
 * Flow control of the caller needs to take care whether a window is returned or false
 * 
 * @constructor showModalDialogHandler(callback) - callback is called, if window is closed.
 *
 */
var showModalDialogHandler = function(callback)
{
    this.modalDialogEmulator = null;
    this.callBack = callback;
    this.returnImmediately = false;
    this.modalDialog = false;
    this.maxRuns = 180;
    this.intervall = 750;
    this.force = false;             // if set to true, emulate always.
    this.chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
    /**
     * make the call, open a dialog, load etc.
     *
     * @param url - URL to load
     * @param arg - args to pass to the window
     * @param feature - featurelist as of window.open
     * @return - erturns a window object (if modal dialogs are supported) or false otherwise
     *
     */
    this.callModalDialog = function(url, arg, feature) {
        var self = this;

        if ( !this.force && window.showModalDialog )
            this.modalDialog = window.showModalDialog(url, arg, feature );
        else
        {
            this.modalDialog = this.modalDialogEmulator(url, arg, feature );
            window.setTimeout(function () {
                self.modalDialog.focus();
            }, 20);

            /*
             * Catch lose focus on main window. Modal dialog should at least
             * stay in front of the opener. If the opener gets focus,
             * window is either shuffled up or closed and reopend (chrome).
             *
             */
            jQuery(window).bind("focus", function() {
                //console.log("opener focus");
                if ( self.chrome )
                {
                    // brute force: close and reopen, hope it will cope with that !!!
                    if( !self.modalDialog.closed )
                    {
                        self.modalDialog.close();
                        self.modalDialog = self.modalDialogEmulator(url, arg, feature );    
                    }
                }
                else
                {
                    if( !self.modalDialog.closed )
                    {
                        window.setTimeout(function () {
                            self.modalDialog.blur();
                            self.modalDialog.focus();
                        }, 30);
                    }
                    else
                    {
                        jQuery(window).unbind("focus"); // remove that listener, cpu-sucker.
                    }
                }
            }); 
        }

        if ( this.returnImmediately )
        {
            var runs = this.maxRuns;
            var loop = setInterval(function() {
                if(self.modalDialog.closed)
                {
                    //console.log("close catched, callback:");
                    clearInterval(loop);
                    self.callBack();
                }
                if ( runs-- <= 0 )
                    clearInterval(loop); // infinitystopper
            }, this.intervall );
            return false;
        }
        else
            return this.modalDialog;

    };

    /*
     * showModalDialog is not longer supported, emulate with popup and
     * a catcher with returnImmediately
     */
    if ( this.force || !window.showModalDialog)
    {
        var self = this;
        this.modalDialogEmulator = function(url, arg, feature) {
            // console.log("window.ShowModalDialog not supported");
            self.returnImmediately = true;
            var opFeature = feature.split(";");
            var featuresArray = new Array()
            if (document.all)
            {
                for (var i = 0; i < opFeature.length - 1; i++)
                {
                    var f = opFeature[i].split("=");
                    featuresArray[f[0]] = f[1];
                }
            }
            else
            {
                for (var i = 0; i < opFeature.length - 1; i++)
                {
                    var f = opFeature[i].split(":");
                    featuresArray[f[0].toString().trim().toLowerCase()] = f[1].toString().trim();
                }
            }

            var h = "200px", w = "400px", l = "100px", t = "100px", r = "yes", c = "yes", s = "no";
            if (featuresArray["dialogheight"]) h = featuresArray["dialogheight"];
            if (featuresArray["dialogwidth"]) w = featuresArray["dialogwidth"];
            if (featuresArray["dialogleft"]) l = featuresArray["dialogleft"];
            if (featuresArray["dialogtop"]) t = featuresArray["dialogtop"];
            if (featuresArray["resizable"]) r = featuresArray["resizable"];
            if (featuresArray["center"]) c = featuresArray["center"];
            if (featuresArray["status"]) s = featuresArray["status"];
            var modelFeature = "height = " + h + ",width = " + w + ",left=" + l + ",top=" + t
                        + ",model=yes,alwaysRaised=yes" + ",resizable= " + r + ",center=" + c
                        + ",dependent=yes,dialog=yes,modal=yes,close=0"
                        + ",status=" + s;

            var model = window.open(url, "modal", modelFeature, null);
            return model;
        };
    }

}

needs jQuery, at least.

Upvotes: 2

Donald Duck
Donald Duck

Reputation: 8882

You can use different codes for different browsers, like this:

if(navigator.userAgent.indexOf("MSIE") != -1){     //If the browser is IE
     //Code for IE
}
else if(navigator.vendor == "Firefox"){            //If the browser is Firefox
     //Code for Firefox
}
else if(navigator.vendor == "Google Inc."){        //If the browser is Chrome
     //Code for Chrome
}

For IE, showModalDialog works just fine and it prevents you from clicking the main page until you close the dialog.
For Firefox, you can use, as you said, showDialogBox.
For Chrome, you can use the thing that niutech suggests.

Otherwise, if you use window.open, all the popup windows will be in the task bar so if they are hidden behind the window, just click on them in the task bar to make them visible.

Upvotes: 2

niutech
niutech

Reputation: 29922

You can use my showModalDialog polyfill using the brand new modal <dialog> element, which works in the latest Google Chrome. A <dialog> polyfill for older browsers is here.

Upvotes: 8

Related Questions