bdn02
bdn02

Reputation: 1500

Javascript -- wait for user interaction without freezing the browser

I don't speak English very well.

My company has developed a web application for internet explorer that very strenuously uses the function showModalDialog and waits for the result.

We are planning to extend the use of the application to other browsers (Firefox, Chrome), and I need to replace "showModalDialog logic" with a logic that will work well on all browsers.

I originally tried using an ajaxcontroltoolkit modalpopup with an iframe inside.

My problem is that, after I have showed the modalpopup, I cannot wait for the user to close the popup window without freezing the web interface.

function OpenDialog() {
    var result = window.showModalDialog("page1.html", "input_parameter", "width:100px; height:100px");

    //When the popup went closed
    alert("result: " + result);
}

//Override showModalDialog function for compatibility with other browser
function myShowModalDialog(url, pars, options) {

    //show a jquery modalpopup or ajaxcontroltoolkit modalpopup with an iframe ....
    iframe.src = url;

    //I need to wait here until the modal popup closed
    //HOW?

    //get the value from popup
    var res = ???????;

    return res;
}

window.showModalDialog = myShowModalDialog;

I cannot change the logic for every page in the webapp.

I searched for a method to override the showModalDialog function and recreate the same logic (wait until the popup is closed and get the result that the popup provides for the caller).

Any ideas? Thanks to all

Upvotes: 2

Views: 2135

Answers (4)

niutech
niutech

Reputation: 29942

Have a look at my showModalDialog polyfill using a modal element and ECMAScript 6 generators, so it does not need an explicit callback function. Statements after showModalDialog() will run after closing the modal.

Upvotes: 0

Pinke Helga
Pinke Helga

Reputation: 6692

I've created a short demo of my suggestion in the comment:

<!DOCTYPE html>
<html>
  <head>
    <title>modal overlay</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
      .overlay
      {
        background-color: rgba(0, 0, 0, 0.1);
        position:absolute;
        top:0;
        left:0;
        width:100%;
        height:100%;
        z-index: 100;
        margin:0;
        display:none;
      }
      .box
      {
        position:absolute;
        top:0;
        left:0;
        bottom:0;
        right:0;
        width:400px;
        height:300px;
        background:white;
        margin:auto;
        padding:10px;
      }

    </style>

    <!--
      prepare a style to show/hide overlay and
      prevent lost focus when clicking outside the box
    -->
    <template id="template1">
      <style id="style-modal">
        *
        { pointer-events: none;
        }
        .overlay *
        {pointer-events: auto;
        }
        .overlay
        { display:block!important;
        }
      </style>
    </template>
  </head>
  <body>
    <input id="some-input1" type="text">
    <button class="modal-open" type="button">open modal dialog</button>

    <div id="overlay1" class="overlay">
      <div class="box">
        <input id="modal-input1" type="text">
        <button type="button" class="modal-close">close</button>
      </div>
    </div>

    <script>
      document.addEventListener
      ( 'DOMContentLoaded',
        function(ev)
        {
          var
            template1  = document.getElementById('template1'),
            styleModal = template1.content.getElementById('style-modal'),
            overlay1   = document.getElementById('overlay1'),
            box        = overlay1.querySelector('.box'),
            head       = document.querySelector('head')
          ;

          //TODO: could iterate over querySelectorAll
          document.querySelector('button.modal-open').addEventListener
          ( 'click',
            function(ev) { head.appendChild(styleModal); },
            false
          )

          overlay1.querySelector('button.modal-close').addEventListener
          ( 'click',
            function(ev)
            { template1.content.appendChild(styleModal);
              document.dispatchEvent(new CustomEvent('closemodal', {detail:{relatedTarget:box}}));
            },
            false
          )
        },
        false
      );

      document.addEventListener
      ( 'closemodal',
        function(ev){ alert(ev.detail.relatedTarget.querySelector('input').value); },
        false
      );
    </script>
  </body>
</html>

Note that this example makes use of <template> element which isn't implemented by IE yet. You can easily generate the style-element in the script, hold it in a variable and add/remove it to/from the head.

Upvotes: 0

mtyson
mtyson

Reputation: 8550

Unless I'm not following you, what you need is a callback when the user closes the dialog, right?

Whatever method is executed when the user closes the dialog, monkey patch it to call your function. (A monkey patch is code that adds functionality to existing code, but keeps the old code also).

So if your close method/function looks like:

myCloseDialog = function(){
  // do important closing stuff
}

Then you can monkey patch like so:

myNewCloseDialog = function(){
  // do important callback stuff, or call your callback function
  myCloseDialog(arguments);
}

By the way, your English is very fine :)

Upvotes: 0

Mike Bell
Mike Bell

Reputation: 1386

You've discovered the reason why JavaScript relies heavily on asynchronicity, event handlers, and callback functions.

The best solution would be to restructure your code so that your events trigger on event handlers, using jQuery or somesuch to bind the event handlers to the event. Alternatively, you could always use a function in a timeout loop to check periodically if the modal is closed yet, and execute the continuation of your code when it is. That's pretty hacky though, and I don't recommend it. In general, trying to force asynchronous code to fit a synchronous model gets really messy.

Upvotes: 2

Related Questions