2

First to clarify, I am trying to open a pop-up in response to a user event.

I am developing an application on Facebook that involves e-commerce transactions, and for reasons related to my EV SSL certificates, I have to open our billing terminal in a new, fully-secure window. As such, the process goes as follows:

  1. User selects "new card" as payment method and enter's the recipient's shipping address
  2. User clicks "Place Order," which uses an AJAX call to validate the address, and IF valid, syncs it with the database.
  3. IF address is valid (AJAX success: function()), and the user selected "new card," then the secure billing terminal is supposed to open using a window.open call.

As I understand it, most modern browsers including Chrome, Firefox, and Safari are supposed to traverse up the chain to determine if the source event was user-initiated (in this case, it was--a click event), however despite this I cannot seem to prevent this pop-up from getting blocked and my users are having a great deal of trouble figuring out what's going on.

Unfortunately Chrome doesn't make it all that noticeable when a pop-up is blocked, so most users will not notice this and will assume that the app is simply "broken."

Any ideas? We're a week from launch and I'm getting desperate...

[EDIT] Here is the code for reference:

/* -- Step 3: Complete Checkout Click -- */

$('div.finishGroupOrder').live('click', function() {

    /* User is Click-Happy? */

    if ( $('div#billing-contents div#loader').length ) {

        alert('Your order is processing.  We know it\'s hard, but please be patient.');
        return false;

    }       

    var paymentMethod   = $('input[name="method"]:checked').val();                      // Payment Method Selected ( Card on File / New / PayPal )

    var secureSession   = $(this).attr('secure');                                   // Secure Session ID

    var orderData       = { addressSelection: $('input[name="address"]:checked').val(),
                        price: $('div.price').attr('value')  };

    /* Form Validation */

    switch( orderData.addressSelection ) {

        case 'new': // User chose to enter address manually

            var allInputs = $('div#new-address').find('input:not(#address2), select');
            var validInputs = $('div#new-address').find('input[value!=""]:not(#address2), select[value!=""]');

            if ( allInputs.length === validInputs.length ) {                            // All inputs are valid, capture their contents

                allInputs.removeClass('bad-value');

                var address = {   phone: $('input#phone').val(),
                               address1: $('input#address1').val(),
                               address2: $('input#address2').val(),
                               city: $('input#city').val(),
                               state: $('select#state').val(),
                               zip: $('input#zipcode').val()  };

                var validatedAddress = validation.validateAddress(address);

                if (validatedAddress) {

                    address.address1    = validatedAddress.address1;
                    address.address2    = validatedAddress.address2;
                    address.city        = validatedAddress.city;
                    address.state       = validatedAddress.state;
                    address.timeOffset  = validatedAddress.timeOffset;              // Time offset from EST (PST = -3, EST = 0, etc.)

                    $('input#timezone').val(address.timeOffset);

                } else {

                    allInputs.addClass('bad-value');
                    return false;

                }

            } else {                                                            // Some inputs are invalid, prompt the user to fix them

                allInputs.filter(function() { return ($.inArray( this, validInputs ) > -1) ? false : true; }).addClass('bad-value');
                return false;

            }

            break;

        case 'verified':    // User chose to ship to verified address

            var address = {   address1: 'verified'  };

            break;

        default:

            alert('Please choose an address where you want the flowers to be delivered.');
            return false;

            break;

    }


    /* Sync Order With Updated Address Information */

    $.ajax({    type: 'POST',
            url: location.protocol + '//' + location.host + '/_ajax/order.ajax.php',
            data: 'action=update_order&' + $.param( address ),

            success: function() {

                /* Load Selected Payment Method */

                switch( paymentMethod ) {

                    //case 'paypal': paypal(); break;

                    case 'member':
                        newGroupOrderDialogActions.payAsMember();
                        break;

                    case 'newCard':
                        newGroupOrderDialogActions.payWithCard( secureSession );
                        //$('div.group-secure-terminal').trigger('click');
                        break;

                }

            }
    });

And the newGroupOrderActions.payWithCard()...

/* -- Pay With a New Credit Card -- */

                                payWithCard: function( session ) {

                                    var windowHeight = 769;         // Terminal Height
                                    var windowWidth = 638;          // Terminal Width
                                    var w = screen.availWidth;      // Available Screen (W)
                                    var h = screen.availHeight;     // Available Screen (H)
                                    var top = (h-windowHeight)/2;       // Center Positioning
                                    var left = (w-windowWidth)/2;       // Center Positioning


                                    /* Open Secure Order Terminal */

                                    var secureTerminal = window.open('https://secure.mydomain.ly/contribute?id=' + session, 'myCompany: Secure Checkout', 'menubar=0,toolbar=0,location=1,resizable=0,scrollbars=1,height='+windowHeight+',width='+windowWidth+',top='+top+',left='+left);


                                    /* Check for Secure Order Terminal Close Event */

                                    var onFinish = setInterval(function() {

                                        try {
                                            if (secureTerminal.closed) {                                                                    // Window has been unloaded, check the order to see if it has been approved

                                                clearTimeout(onFinish);

                                                $.ajax({    type: 'POST',
                                                        url: location.protocol + '//' + location.host + '/_ajax/redirect.ajax.php',
                                                        data: 'action=group_order_status_redirect',
                                                        success: function(redirect) { newGroupOrderDialogActions.publishOrder( redirect ) }         // If redirect is not null, order was successful.  Redirect to order page   
                                                });
                                            }
                                        } catch (e) {}

                                    }, 200);

                                },
Julian
  • 1,406
  • 1
  • 13
  • 24
  • 2
    Could we see your JS that initiates the popup? Or could you isolate and post it to http://jsfiddle.net ? – LoveAndCoding Jan 23 '12 at 21:32
  • 1
    As I understand it, you're opening the popup in the success handler, which can happen at an arbitrary moment in time, and not as a direct response to a click event. Technically, if this was allowed (I think this is the problem of the blocking) you could have the server wait a specific amount of time and then send a response, causing a popup to show, even though the user doesn't click anything at that moment. – pimvdb Jan 23 '12 at 21:35
  • @pimvdb is correct. If you are opening it in the success function, it is not from a user event anymore. I'd recommend posting that as an answer pimvdb – LoveAndCoding Jan 23 '12 at 21:43
  • I'm not entirely sure if that's the reason, nor do I actually know a real answer. You could try `async: false` in the ajax request (I'm not sure if that blocks just the extension or the whole webpage). Does that work? – pimvdb Jan 23 '12 at 21:47
  • Seeing the code, I would say @pimvdb is likely correct. You are calling `window.open` from within the AJAX response, which is no longer considered a user action. – LoveAndCoding Jan 23 '12 at 21:57
  • possible duplicate of [Popup blocked, jquery window.open in success: AJAX? outside ok](http://stackoverflow.com/questions/1086672/popup-blocked-jquery-window-open-in-success-ajax-outside-ok). Looking at your code, I think this question already addressed this issue with an answer. – pimvdb Jan 23 '12 at 22:00
  • I'm testing out the async: false right now, but I'm a little wary even if that works because I know it freezes the entire browser in Firefox until the response has been received. From a usability standpoint I would like to avoid this if possible. – Julian Jan 23 '12 at 22:04
  • And I saw the question you linked to, I'm just trying to figure out if there is any way to avoid using the async: false due to browser usability concerns... That method seems like a good last resort, but I feel like there should be another way? – Julian Jan 23 '12 at 22:06
  • UPDATE: the `async: false` method in the first answer from the solution linked above is not working in Chrome regardless – Julian Jan 23 '12 at 22:16
  • It appears to be fine in both Firefox and Safari however – Julian Jan 23 '12 at 22:25
  • This might be a bug in Chrome, because the call stack should NOT be lost when you are executing `window.open` inside a `synchronous` AJAX call. – Julian Jan 23 '12 at 22:37

0 Answers0