PINSystems Source Samples:
busyDialog
  SourceSamples Home

Launch Sample   Source Code

While working on a PhoneGap based mobile app I was unable to locate/implement the notification dialog api. After spending the better part of a day on researching what should have been a trivial task, I decided to build one for myself. Since PhoneGap is HTML/CSS/Javascript based, the logic applies to a broader base.

The concept: Create a background div (100% height/100% width) with a 60% opacitiy and another div for the modal dialog.
The reality: Nothing is as simple as it sounds.

Problems encountered...
  • Opacitiy of the background/bottom div bleeding through the dialog/top div no matter what z-ordering or how they were created (parent/child or sibling).

  • Control functionality bleeding through multiple divs (background and dialog). By this I mean that even though covered, clicking on or "touching" <select> elements displayed the focus border and drop-down/popup lists on top of the divs. <input> elements would also display their focus borders when clicked/touched.

  • Animated gif running and "stacking-up"/"building pressure" when it should have been destroyed. This is a hard one to describe but when the dialog containing an animated gif in an <img> tag was closed and removed from the DOM, the gif was still active in some sense. If you waited 10 seconds and relaunched the dialog, the gif would "run" in high speed until those 10 seconds worth of frames were displayed. Then it would resume normal speed. Not an "error", but not what you're going for.

  • JavaScript organization. Not a problem, but it looks like I'm finally going to have to write a lot of JavaScript. It was time to work on implementing nested namespaces and "classes" (OOP-esque features). I think this implementation is close to what I'll use moving forward. It'll be addressed/documented in my next update to the site.


  • Resolutions...
    Opacity Bleed
    This is a case where I should have given up sooner. Long story short, I could not get the opacity to stop bleeding through to the modal dialog div. So, I created a very small 60% opaque image and set the background of the bottom div to it.

    Control Bleed
    No matter which background div iteration was used (css opacity or image opacity), <select> elements were actve (including click events) and <input>/<button> elements would receive focus but not execute their click events.
    This was addressed by writing two JavaScript methods, one to store the current disabled state and disable each control in a tree. Another to re-enable the controls in the tree, respecting the original disabled state. The original disabled state is stored to a custom attribute (lastDisabled) on each element before disabling.

    GIF "Building Pressure"
    This one was fairly simple to resolve... When closing the dialog, before removing the background <div> from the DOM, change the <img>'s src property to an empty string.

    Source Code...
    The following busyDialog implementation is from index.html.

    /* The following might not be neeed in future implementations,
    * but in this one it's needed to initialize the JavaScript
    * bdSample namespace, making static methods avaialble.
    */
    bdSample_init();

    /* A page level busyDialog object */
    var bd = new bdSample.busyDialog();

    function loginClicked()
    {
    /* Display the modal dialog */
    bd.show("The modal message...", true, "images/ajax-loader-green-bar.gif");

    /* This is where you'd start an asynchronous post, passing loginPostComplete */

    /*Since we're not posting... Lets wait 5 seconds then reenable by calling loginPostComplete() */
    window.setTimeout("javascript:loginPostComplete();", 5000);
    }

    function loginPostComplete(responseData, status)
    {
    /* Process the response */

    /*Close the modal dialog */
    bd.close();
    }

    The meat of the functionality is contained in scripts/bdSample.util.js and scripts/bdSample.busyDialog.js.

    bdSample.util.js:
    bdSample.util.disableControls()

    Disables all elements in the passed element's child tree. If no element is passed, it looks for and processes a default element ("ControlsContentDiv"). Before disabling each element, the element's current disabled state is stored in a "lastDisabled" attribute on that element (for use when re-enabling).
    You'll see that <option> elements are skipped. This is done for two reasons: 1) If the select is disabled they're irrelevant and most importantly... 2) They don't "re-enable" properly (I didn't spend any time researching why).


    bdSample.util.reEnableControls()

    Enables all elements in the passed element's child tree. If no element is passed, it looks for and processes a default element ("ControlsContentDiv"). Being the sister to disableControls(), before automatically enabling all controls, it attempts to retrieve the "lastDisabled" attribute. If it's not present or false, the control is enabled (disabled = false).


    The following are included merely because I seem to be using them more and more. I also have a variation that processes a "column" of TDs.

    bdSample.util.sizeButtonsToRowOfTDs()

    Pass in the "id" of a <tr>. The method looks in all <td>s for <button> elements. When one is found, it's passed to sizeButtonToTD() for sizing.


    bdSample.util.sizeButtonToTD()

    Pass a <td> object and if it contains a <button>, it's sized to match the <td> (optionally sizing height and/or width)


    bdSample.busyDialog.js:
    These are best described by looking at the source.
    bdSample.busyDialog.show()
    bdSample.busyDialog.close()


    Screenshot...





    4/17/2012 PINSystems.com