/*!
  modalize plug-in for jQuery, License - MIT, Copyright 2009 Traversal: http://traversal.com.au
*/

/*
  Title: modalize plug-in
    
  Description:
    Creates a div underlay element under the target element, to screen anything below and prevent clicking, as required by a modal window.
    The <modalize> function also shows the underlay immediately, and another plug-in function <unmodalize> is also provided to hide the underlay. 
    
  Note:
    This plug-in doesn't actually handle presentation of the element you want to make modal, it simply provides a screening element underneath.

  Author Info:
    Created By - Traversal <http://traversal.com.au>
    Licence - MIT Style <http://en.wikipedia.org/wiki/MIT_License>

  Requires: 
    jQuery 1.3 - http://jquery.com

  Companion plug-ins:
    Metadata - http://plugins.jquery.com/project/metadata (optional)

*/


(function($) { // closure and $ portability
  
  /*
     Property: defaults
       Default options for modalize, which may be configured for all calls.  See <modalize> for available options and their default values.

     Example Usage:
       > jQuery.fn.modalize.defaults.css.opacity = 0.5; // default opacity is now 0.5

 */
    
  var defaults = {
    className: "modal-underlay",
    css: { opacity: 0.7, backgroundColor: "#000" },
    hideDocumentScrollbars: false,
    fadeIn: false,
    fadeOut: false,
    fade: false,
    fadeOptions: {duration: "fast"},
    fadeInOptions: {duration: "fast"},
    fadeOutOptions: {duration: "fast"},
    layerfix: { method: "hideSelects" } // layerfix options hash, so that selects are not rendered on top of the element e.g. { method: "hideSelects" } where method should be false || "hideSelects" || "shim" || "both"  (requires layerfix plugin)
  };


  /* 
    
    Function: modalize
      creates and shows a div underlay element for making the target "modal".
  
    Arguments: 
      options - Object, the options hash to configure the plug-in (see below)

    Options (defaults shown in brackets): 
      className ( "modal-underlay" )                        - String, the css class name applied to the modal underlay
      css ( { opacity: 0.8, backgroundColor: "#000" } )     - Object, a hash of CSS key / value pairs to apply to the underlay. Since this uses jQuery's *css* function, it makes things like opacity easier to implement cross-browser
      hideDocumentScrollbars ( false )                      - Boolean, if true, the main document scrollbars will be hidden (by setting the body's overflow to hidden). 
                                                              This is not supported in IE 6. Note that a subsequent call to "unmodalize" will then restore the body overflow.
      fadeIn (false)                                        - Boolean, if true, jQuery's fadeIn method will be used to show the underlay
      fadeInOptions ( { duration: "fast" } )                 - Object, a hash of params to use for jQuery's fadeIn method, if the fadeIn option is set to true
      fadeOut (false)                                       - Boolean, if true, jQuery's fadeIn method will be used to hide the underlay
      fadeOutOptions ( { duration: "fast" } )                - Object, a hash of params to use for jQuery's fadeOut method, if the fadeOut option is set to true
      fade (false)                                          - Boolean, a shortcut to set both the fadeIn and fadeOut options to true
      fShow (null)                                          - Function, if passed this function will be used to show the underlay, with the underlay element as its single argument     
      fHide (null)                                          - Function, if passed this function will be used to hide the underlay, with the underlay element as its single argument     
      
    Example:
  
      > $('button#add-product').click( function(event) {
      >   $('#modal-add-product').modalize().fadeIn("fast");
      > });

  */


  $.positionFixed = function () { var isSupported = null; { var el = $('<div>').css({width: 1, height: 1, position: 'fixed', top: 10}).appendTo("body"); isSupported = (el.offset().top == 10); el.remove(); } return isSupported; }; 

  var pn = 'modalize';
  $.fn[pn] = function() {
    
    // patch in a support property to check for fixed position support
    $.support.positionFixed = $.support.positionFixed || $.positionFixed(); // cache the result 
    
    var cmd, options = {}, params = {}, a = arguments; if (a.length >= 1) { if (typeof(a[0]) == "string") { cmd = a[0]; } else { options = a[0]; } if (a.length >= 2) { params = a[1]; } }
    
    return this.each( function() {

      
      var d, p = params, o = {}, md = {}, el = $(this); if ($.fn.metadata) { md = el.metadata(); } if (!cmd) { d = el.data(pn); if (!d) { d = {}; el.data(pn, d); } $.extend(true, o, defaults, options, md[pn] || md || {} ); d.options = o; } else { d = el.data(pn); if (d) { o = d.options; } else { return; } }

      
      var size = { width: Math.max($("body").width(), $(window).width(), $(document).width()), height: Math.max($("body").height(), $(document).height(), $(window).height()) };
      
      if (o.fade) { 
        o.fadeOut = true; o.fadeIn = true; 
        
        o.fadeOutOptions = o.fadeOptions;
        o.fadeInOptions = o.fadeOptions;
      }
      
      if (!cmd) {
        

        var z = el.css("z-index");

        if (z <= 0 || z == "auto") {
            d.savez = z;
            el.css("z-index", 1);
        }

        if (z == "auto") {
          z = 0;
        }
        
        if (!d.underlay) {
          //  the underlay doesn't exist, so create it and store against the element
          d.underlay = $('<div class="' + o.className + '"></div>').appendTo("body");
        }
        
        
        d.underlay.css({position: "absolute"});
        
        d.underlay.css($.extend(true, {}, o.css, {
          "zIndex"   : Math.max(z - 1, 0), 
          "width"     : size.width, 
          "height"    : size.height, 
          "left"      : 0, 
          "top"       : 0,
          "display"   : "none"
        }));
        
        
        if ($.support.positionFixed) {
          d.underlay.css({position: "fixed"});
        }

        var soncomplete = function() {
          
          if (o.layerfix && el.layerfix) {
    			    el.layerfix(o.layerfix);
    			}
          
          
          if (o.fade && o.fadeInOptions.complete) {
            o.fadeInOptions.complete();
          }
        };

        
        if (o.fshow) {
          o.fshow(d.underlay);
          soncomplete();
        }
        else if (o.fadeIn) {
          d.underlay.fadeIn($.extend(true, {}, o.fadeInOptions, {complete: soncomplete}));
        } else {
          d.underlay.show();
          soncomplete();
        }

        if (o.hideDocumentScrollbars) {
          $("body").css("overflow", "hidden");
        }

        if (!d.underlayClick) {
          
          d.underlayClick = function() {
            el.trigger("underlayclick.modalize", [{ underlay: d.underlay }]);
          };
        
          d.underlay.click(d.underlayClick);
        }
        
        
        if (!d.windowOnResize) {
    	    
    	    d.windowOnResize = function(event) { 
    	      if (el) { 
    	        el.modalize('again'); 
    	      } 
    	    };
    	    
          $(window).resize(d.windowOnResize);
        }
        
      }
      else if (cmd == 'hide') {
        
        $(window).unbind("resize", d.windowOnResize);
        d.windowOnResize = null;

        if (o.hideDocumentScrollbars) {
          $("body").css("overflow", "auto");
        }

          
        if (d.underlay) {
          
          // we won't destroy the underlay, we'll just hide it
          
          var honcomplete = function() {

            if (o.layerfix && el.layerfix) {
      			  el.layerfix('remove');
      			}
            
            if (d.savez !== null) {
             el.css("z-index", d.savez);
             
             if (o.fade && o.fadeOutOptions.complete) {
               o.fadeOutOptions.complete();
             }
            }
            
            d.underlay.hide();
          };
          
          if (o.fhide) {
            o.fhide(d.underlay);
            honcomplete();
          }
          else if (o.fadeOut) {
            d.underlay.fadeOut($.extend(true, {}, o.fadeOutOptions, {complete: honcomplete}));
          } else {
            d.underlay.hide();
            honcomplete();
          }

        }
        
      }
      else if (cmd == 'resize' || cmd == 'again') {
        if (d.underlay.is(":visible")) {
          var size = { width: Math.max($("body").width(), $(window).width(), $(document).width()), height: Math.max($("body").height(), $(document).height(), $(window).height()) };
          d.underlay.css(size);
        }
      }
      else if (cmd == 'destroy') {
        el.modalize('hide');
        d.underlay.remove();
        
        if (o.layerfix && el.layerfix) {
  			  el.layerfix('destroy');
  			}
        
        
        el.removeData('modalize');
      }
      
    });
    
  };

  /* 
    
    Function: unmodalize
      Hides the div underlay previously created by <modalize>. Note that modalize creates the underlay element on the fly, but
      this functon doesn't delete the underlay element from the DOM (for efficiency, in case it needs to be shown again)
  
    Example:
      
      > $('button.modal-close').click( function(event) {
      >   $(this).closest(".modal").hide().unmodalize();
      > });

  */
  
  $.fn.unmodalize = function() {
    return this.modalize('hide');      
  };
  
  /* 
    
    Function: remodalize
      Resizes the div underlay previous created by <modalize>. Note that this function is called for you automatically as the window is resized. 

  */
  
  
  $.fn.remodalize = function() {
    return this.modalize('again');
  };
  
  
  $.fn[pn].defaults = defaults; // expose default options
  
})(jQuery);
