Avatar of mmoore
mmoore
Flag for United States of America asked on

on window close, not beforeunload

I have a parent window which has a button which launches a popup window. The first thing the popup window does is to mask-out the parent window so that no data can be entered while the popup is open. The popup window is like a wizard which presents a series of forms with PREVIOUS and NEXT buttons. When the last form is presented, there is a FINISH button. When the user clicks on the FINISH button, the mask-out is removed from the parent window and then the popup window closes. This works perfectly. The only problem is, what happens if the user closes the window prior to reaching the FINISH button? Well, the parent window remains masked-out. I tried adding the following bit of code to the popup window.
  window.addEventListener('beforeunload', function () { 
     window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
   });

Open in new window

It works nicely when the user closes the popup window. Unfortunately it also triggered when the user hits the NEXT button. The NEXT button looks like:
<input id="j_id0:j_id1:i:f:pb:pbb:next" type="submit" name="j_id0:j_id1:i:f:pb:pbb:next" value="Next" style="visibility: visible;" class="btn FlowNextBtn">

Open in new window

I don't understand why the 'beforeunload' event is being triggered by the NEXT button.
I've tried various ways of unbinding the 'beforeunload' event from the <FORM> but no luck.
What do I need to do in order to unmask the window.opener.document when the user closes the popup but not when they click on the NEXT button.
Thanks
JavaScript

Avatar of undefined
Last Comment
Julian Hansen

8/22/2022 - Mon
mmoore

ASKER
I have solved my problem by using MutationObserver. I trap it when somebody changes the class on the DIV which causes the shield to drop. I then test if the popup still exists. If Yes, then I put the shield back down. Shield down means:

 window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");

So rather that find the source of the problem and prevent it, I have chosen to monitor the symptom and fix it.
Julian Hansen

You need to post a message the parent window.

Parent
CSS
<style type="text/css">
.overlay {
  background: rgba(0,0,0,.85);
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 10000;
}
</style>

Open in new window

HTML
	<button>Click Me</button>

Open in new window

JavaScript
<script>
$(function() {
  $('button').click(function() {
    $('body').append($('<div/>', {class: 'overlay'}));
    window.open('t2196child.html');
  });
});
window.addEventListener('message', function(e) {
  console.log(e.data);
  $('.overlay').remove();
}, false);
</script>

Open in new window

Child
<!doctype html>
<html>
<body>
<h1> Close this form</h1>
<script>
window.addEventListener('beforeunload', function() {
	window.opener.postMessage("done", window.location.href);
});
</script>
</body>
</html>

Open in new window

Working sample here
mmoore

ASKER
I should have made it more clear that the NEXT button is also triggering a 'beforeunload' event, and I can't change this because it's part of a visual flow (salesforce) embedded in a visualforce page. I don't need need anybody to look at this, but I am posting in just in case anybody is interested.
<apex:page showheader="false" sidebar="false">
<flow:interview name="New_Account_Wizard"></flow:interview>
<!-- New_Account_Wizard is a multi page flow with a form on each page -->
<!-- so at different stages of the flow the DOM will look different -->   
<script>

   window.onload = function () {
     var frm = document.getElementById('j_id0:j_id1:i:f');
     // do this only if the target FORM is on the curent page
     if (typeof(frm) != 'undefined' && frm != null)
     {
     
        var accountNameField = document.getElementById('j_id0:j_id1:i:f:pb:d:Company.input');
        // do this only if the target accountNameField is on the curent page
        if (typeof(accountNameField) != 'undefined' && accountNameField != null)
        {
           // Load the local Storage when the user hits the NEXT button. NEXT button does SUBMIT and goes to next page
           frm.addEventListener('submit',function(evt) {
               localStorage.setItem('AccountName', document.getElementById('j_id0:j_id1:i:f:pb:d:Company.input').value);
           });
        }
     }
     
     var finishBtn = document.getElementById('j_id0:j_id1:i:f:pb:pbb:finish');
     if (typeof(finishBtn) != 'undefined' && finishBtn != null)
     {
        // override the FINISH button on the last screen of the wizard. If you dont,
        // the natural behaviour is to restart the wizard at page one.
        finishBtn.addEventListener('click',function(evt2) {
            evt2.preventDefault();
            //console.log (document.body);
            //var list = (opener.document.body)
            
            // Remove backdrop which is covering the parent window
           // window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
            //console.log (list);

            window.close();
        });
     }
   }

    
 window.addEventListener('beforeunload', function () { 
 
    window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
    console.log('opened backdrop from popup window');
  });

</script> 
</apex:page>

Open in new window


The "<flow:interview name="New_Account_Wizard"></flow:interview>" basically injects a Visual Flow ( a multi form multi page web based app) at this point. This app has a NEXT button on it with takes the user to the next page but it ALSO also triggering a 'beforeunload'. I don't want to unmask the parent window each time the user hits the NEXT button. I only want to unmask  the parent window when the user actually closes the popup. Anyway, I've actually solved my problem albeit a bit hacky.  I'll leave this open for now just in case there is some solution that allows me differentiate between the user clicking on the close-window X button and hitting the NEXT button.
Capture.PNG
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
ASKER CERTIFIED SOLUTION
Julian Hansen

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
mmoore

ASKER
Awesome idea. I'll try that. It's a good technique. I doubt, however,  if it is the best solution in this case because the wizard (visual flow) might be changed independent of this usage. I think that each NEXT button might have a different id and if more next buttons get created (more pages to the wizard)  then I would need to update my wrapper to address these new buttons. In fact, that is a weakness that my wrapper (visualforce page shown above) already has. It looks for specific element ids and I have no guarantee  that the next time I generate the visual flow that it will be generated with those same ids.  Thanks for your help!
Julian Hansen

I would look for something that identifies the button other than its id - look for a class that you can use - even if it is a sibling you can do a next to get to the Next button.

Otherwise you are welcome.