// $Id: popups.js,v 1.9.4.7 2009/01/15 02:09:44 starbow Exp $

/**
 * Popup Modal Dialog API
 *
 * Provide an API for building and displaying JavaScript, in-page, popups modal dialogs.
 * Modality is provided by a fixed, semi-opaque div, positioned in front of the page contents.
 *
 */


//"<div id="popups"><div id="popups-title"><div id="popups-close"><a href="#">Close</a></div><div class="title">Popups Settings</div><div class="clear-block"></div></div><div id="popups-body"><form action="/drupal-5/admin/settings/popups?Array" accept-charset="UTF-8" method="post" id="popups-admin-settings">\n<div><div class="form-item">\n <label class="option"><input type="checkbox" name="popups_popup_final_message" id="edit-popups-popup-final-message" value="1" checked="checked" class="form-checkbox" /> Do NOT auto-close final message.</label>\n</div>\n<input type="submit" name="op" id="edit-submit" value="Save configuration" class="form-submit" />\n<input type="submit" name="op" id="edit-reset" value="Reset to defaults" class="form-submit" />\n<input type="hidden" name="form_token" id="edit-popups-admin-settings-form-token" value="b82bd6be9f3700b6130c6f05da525c50" />\n<input type="hidden" name="form_id" id="edit-popups-admin-settings" value="popups_admin_settings" />\n\n</div></form>\n</div><div id="popups-buttons"></div><div id="popups-footer"></div></div>"

/**
 * Create the popups object/namespace.
 */
Drupal.popups = function() {};

function isset(v) {
  return (typeof(v) !== 'undefined');
}

/**
 * Attach the popups bevior to the all the requested links on the page.
 *
 * @param context
 *   The jQuery object to apply the behaviors to.
 */
Drupal.popups.behavior = function(context) {
//console.log("Attaching popups");
  var $body = $('body');
  if ($('body.popups-processed').size() === 0) {
//        if(!$body.hasClass('popups-processed')) {
    $(document).bind('keydown', Drupal.popups.keyHandle);
    $body.addClass('popups-processed');
  }
  
  // Add the popups-link-in-dialog behavior to links defined in Drupal.settings.popups.links array.
  if (Drupal.settings.popups.links) {
    jQuery.each(Drupal.settings.popups.links, function (link, options) { 
      Drupal.popups.attach(context, link, options);
    });
  }
/*  if (Drupal.settings.popups) {
    for (var link in Drupal.settings.popups.links) {
      var options = Drupal.settings.popups.links[link];
      Drupal.popups.attach(context, link, options); // Needs to be seperate function for closure.
    }
  }
*/  
  Drupal.popups.attach(context, '.popups', {noReload: true});  
  Drupal.popups.attach(context, '.popups-form', {noReload: false});  
};

/**
 * Attach the popups behavior to a particular link.
 *
 * @param selector
 *   jQuery selector for links to attach popups behavior to.
 * @param options
 *   Hash of options associated with these links.
 */
Drupal.popups.attach = function(context, selector, options) {
  $(selector, context).not('.popups-processed').each(function() {
    var $element = $(this);
    // Mark the element as attached.    
    var title = $element.attr('title') || '';
    $element.attr('title', title + '[Popup]'); // Append note to link title.
    $element.addClass('popups-processed');
    
    // Attach the on-click popup behavior to the element.
    $element.click(function(e){ 
      var element = this;

      // If element is inside of a #popup div, show alert and bail out. 
      if ($(element).parents('#popups').length) { 
        alert("Sorry, popup chaining is not supported (yet).");
        return false;
      }

      // If the element contains a on-popups-options attribute, use it instead of options param.
      if ($(element).attr('on-popups-options')) {
        options = eval( '(' + $(element).attr('on-popups-options') + ')' ); 
        // eval('options = ' + $(element).attr('on-popups-options'));
      }

      // If the option is distructive, check if the page is already modified, and offer to save.
      var pageIsDirty = $('span.tabledrag-changed').size() > 0;
      var willModifyOriginal = !options.noReload;
//    console.log ( "LOG: pageIsDirty && willModifyOriginal:" + pageIsDirty + ', '+ willModifyOriginal);
      if (pageIsDirty && willModifyOriginal) {
        // The user will lose modifications, so popups dialog offering to save current state.
        var body = "There are unsaved changes on this page, which you will lose if you continue.";
        var buttons = {
         'popup_save': {title: 'Save Changes', func: function(){Drupal.popups.savePage(element, options);}},
         'popup_submit': {title: 'Continue', func: function(){Drupal.popups.removePopup(); Drupal.popups.openPath(element, options);}},
         'popup_cancel': {title: 'Cancel', func: Drupal.popups.close}
        };
        return Drupal.popups.open( 'Warning: Please Confirm', body, buttons );
      }
      else {
        return Drupal.popups.openPath(element, options);
      } 
    });    
  });
};

/**
 * Attach Drupal behaviors to new html
 *   Tricky because Drupal 5 doesn't think like this. 
 */
Drupal.popups.attachBehaviors = function($context, options) {
//console.log("Attaching Behaviors");
  Drupal.popups.behavior($context); // this one is easy :)
  if (options.behaviors) {
    jQuery.each(options.behaviors, function () { 
      eval('' + this + '($context)');
    }); 
  }
/*  
    for (var i in options.behaviors) {
      var behavior = options.behaviors[i];
//      console.log("eval " + behavior);
      eval(behavior + '($context)');
    }  
  }
  */
}; 


/**
 * Generic dialog builder.
 */
Drupal.popups.open = function(title, body, buttons, width) {
  Drupal.popups.addOverlay(); // TODO - nonModal option.
  // Weird that we need to strip out the \n's.  Not a problem in jQuery 1.2
  var popup = Drupal.popups.themePopupDialog(title, body, buttons).replace(/\n/g, '');
  var $popups = $(popup);
  // Start with dialog off the side. Making it invisible causes flash in FF2.
  $popups.css('left', '-9999px');
  if (width) {
//    console.log ("setting width to " + width);
    $popups.width(width);
  }
  $('body').append( $popups ); // Add the popups to the DOM.

  // Adding button functions
  if (buttons) {
    jQuery.each(buttons, function (id, button) { 
      $('#'+id).click(button.func);
    }); 
  }
  /*    
  if (buttons) {
    for (var id in buttons) {
      if (buttons[id]) { // to make jslint happy.
        var func = buttons[id].func;
        $('#'+id).click( func );
      }
    }
  }*/
  $('#popups-close').click( Drupal.popups.close );
  $('a.popups-close').click( Drupal.popups.close );
    
  // center on the screen, adding in offsets if the window has been scrolled
  var popupWidth = $popups.width();  
  var windowWidth = $(window).width();
  var left = (windowWidth / 2) - (popupWidth / 2) + Drupal.popups.scrollLeft();
  
  // Get popups's height on the page.
  // Causes flash in FF2 if popups is not visible!
  var popupHeight = $popups.height(); 
  var windowHeight = $(window).height();
  if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window.
    popupHeight = 0.9 * windowHeight;
    $popups.height(popupHeight + 'px');
  }  
  var top = (windowHeight / 2) - (popupHeight / 2) + Drupal.popups.scrollTop();

  $popups.css('top', top+'px').css('left', left+'px'); // Position the popups to be visible.
  
  this.refocus(); // TODO: capture the focus when it leaves the dialog.
  Drupal.popups.removeLoading(); // Remove the loading img.
   
  return false;
};

/**
 *  Simple popups that functions like the browser's alert box.
 */
Drupal.popups.message = function(title, message) {
  message = message || '';
  var buttons = {
    'popup_ok': {title: 'OK', func: Drupal.popups.close}
  };
  Drupal.popups.open(title, message, buttons);
};

/**
 * Handle any special keys when popups is active.
 */
Drupal.popups.keyHandle = function(e) {
  if (!e) {
    e = window.event;
  }
  switch (e.keyCode) {
    case 27: // esc
      Drupal.popups.close();
      break;
    case 191: // '?' key, show help.
      if (e.shiftKey && e.ctrlKey) {
        var $help = $('a.popups.more-help');
        if ($help.size()) {
          $help.click();
        }
        else {
          Drupal.popups.message("Sorry, there is no additional help for this page");
        }
      }
      break;
  }
};

/*****************************************************************************
 * Appearence Functions (overlay, loading graphic, remove popups)     *********
 *****************************************************************************/

Drupal.popups.removePopup = function() {
  $('#popups').remove();  
}; 
 
Drupal.popups.addOverlay = function() {
  var $overlay = $('#popups-overlay');
  if (!$overlay.size()) { // Overlay does not already exist, so create it.
    $overlay = $(Drupal.popups.themePopupOverlay());
    $overlay.css('opacity', '0.4'); // for ie6(?)
    // Doing absolute positioning, so make overlay's size equal the entire body.
    $doc = $(document);
    $overlay.width($doc.width()+'px').height($doc.height()+'px'); 
    $overlay.click(Drupal.popups.close);
    $('body').prepend($overlay);
  }
};

Drupal.popups.removeOverlay = function() {
  $('#popups-overlay').remove();
};

Drupal.popups.addLoading = function() {
  var $loading = $('#popups-loading');
  if (!$loading.size()) { // Overlay does not already exist, so create it.
    var waitImageSize = 100;
    var left = ($(window).width() / 2) - (waitImageSize / 2)  + Drupal.popups.scrollLeft();
    var top = ($(window).height() / 2) - (waitImageSize / 2)  + Drupal.popups.scrollTop();
    $loading = $(Drupal.popups.themePopupLoading(left, top));
    $('body').prepend($loading);
  }
};

Drupal.popups.removeLoading = function() {
  $('#popups-loading').remove();
};

/**
 * Remove everything.
 */
Drupal.popups.close = function() {
  Drupal.popups.removePopup();
  Drupal.popups.removeLoading();
  Drupal.popups.removeOverlay();
  return false;
};

/**
 * Set the focus on the popups to the first visible form element, or the first button, or the close link.
 */
Drupal.popups.refocus = function() {
  $focus = $('#popups input:visible:eq(0)');
  if (!isset(focus)) {
    $focus = $('#popups-close'); // Doesn't seem to work.
  }
  $focus.focus();
};

/****************************************************************************
 * Theme Functions   ********************************************************
 ****************************************************************************/

Drupal.popups.themePopupLoading = function(left, top) {
  var loading = '<div id="popups-loading">';
  loading += '<div style="left:' + left +'px; top:' + top +'px;">';
  loading += '<img src="'+ Drupal.settings.popups.modulePath + '/ajax-loader.gif" />';
  loading += '</div></div>';
  return loading;
};

Drupal.popups.themePopupOverlay = function() {
  return '<div id="popups-overlay"></div>';
};

Drupal.popups.themePopupButton = function(title, id) {
  return '<input type="button" value="'+ title +'" id="'+ id +'" />';
};

Drupal.popups.themePopupDialog = function(title, body, buttons) {
  var themedButtons = '';
  if (buttons) {
    jQuery.each(buttons, function (id, button) { 
      themedButtons += Drupal.popups.themePopupButton(button.title, id);
    });  
  }
/*  for ( var id in buttons) {
    if (buttons[id]) {
      themedButtons += Drupal.popups.themePopupButton(buttons[id].title, id);
    }
  } */

  var popups = '<div id="popups">' +
    '<div id="popups-title">' +
    '<div id="popups-close"><a href="#">Close</a></div>' +
    '<div class="title">' + title + '</div>' +
      '<div class="clear-block"></div>' +
    '</div>' +
    '<div id="popups-body">' + body + '</div>' +
    '<div id="popups-buttons">' + themedButtons + '</div>' +
    '<div id="popups-footer"></div>' + 
    '</div>';
  
  return popups;
};

// FROM jQuery offset
// add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
//     box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));

Drupal.popups.scrollLeft = function() {
  return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
};

Drupal.popups.scrollTop = function() {
  return Math.max(document.documentElement.scrollTop, document.body.scrollTop);
};

/****************************************************************************
 * Page & Form in popups functions                                         ***
 ****************************************************************************/

/**
 * Use Ajax to open the link in a popups window.
 *
 * @param element
 *   Element that was clicked to open the popups.
 * @param options
 *   Hash of options controlling how the popups interacts with the underlying page.
 */
Drupal.popups.openPath = function(element, options) {
  // let the user know something is happening
  $('body').css("cursor", "wait");
  
  // TODO - get nonmodal working.
  if (!options.nonModal) {
    Drupal.popups.addOverlay(); 
  }
  Drupal.popups.addLoading();
  
  var href = options.href ? options.href : element.href;

  $.ajax({
    url: href,
    dataType: 'json',
    beforeSend: Drupal.popups.beforeSend,
    success: function(json) { 
      Drupal.popups.openContent(json.title, json.messages + json.content, options);
    },
    error: function() {
      Drupal.popups.message("Unable to open: " + href);
    },
    complete: function() {
      $('body').css("cursor", "auto"); // Return the cursor to normal state.      
    }
  });
  
//  $.getJSON(href, function(json) { 
//    Drupal.popups.openContent(json.title, json.messages + json.content, options);
//    $('body').css("cursor", "auto"); // Return the cursor to normal state.  
//  });
         
  return false;         
};

/**
 * Open content in an ajax popups.
 *
 * @param title
 *   String title of the popups.
 * @param content
 *   HTML to show in the popups.
 * @param options
 *   Hash of options controlling how the popups interacts with the underlying page.
 */
Drupal.popups.openContent = function(title, content, options) {
  Drupal.popups.open(title, content, null, options.width); 
  // Add behaviors to content in popups. 
  Drupal.popups.attachBehaviors($('#popups-body'), options);
  Drupal.popups.refocus();
//return;

  // If the popups contains a form, capture submits.
  var $form = $('form', '#popups-body');
  $form.ajaxForm({   
    dataType: 'json',   
    beforeSend: Drupal.popups.beforeSend,
    before: Drupal.popups.beforeSubmit,
    success: function(response, status) {
      Drupal.popups.formSuccess(response, options);
    },
    error: function() {
      Drupal.popups.message("Unable to process reply.");
    }
  });
};

Drupal.popups.beforeSend = function(xhr) {
//  console.log('beforeSend');
  xhr.setRequestHeader("X-Drupal-Render-Mode", 'json/popups');
};

/**
 * Do before the form in the popups is submitted.
 */
Drupal.popups.beforeSubmit = function(formData, $form, options) {
//  console.log('beforeSubmit');
  Drupal.popups.removePopup(); // Remove just the dialog, but not the overlay.
  Drupal.popups.addLoading();
//  console.log("Before Submit");
};

/**
 * The form in the popups was successfully submitted
 * Update the originating page.
 * Show any messages in a popups (TODO - make this a configurable option).
 * 
 * @param response
 *   JSON object from server with status of form submission.
 * @param options
 *   Hash of options controlling how the popups interacts with the underlying page.
 *     noReload: bool, does the popups effect the underlying page.
 *     nonModal: bool, does the popups block access to the underlying page.
 *     targetSelectors: array (or hash) of jQuery selectors, overrides defaultTargetSelector.
 *     titleSelectors: array of jQuery selectors, where to put the the new title of the page.
 */
Drupal.popups.formSuccess = function(data, options) {  
  // Determine if we are at an end point, or just moving from one popups to another.
  var done = location.href.match(data.path) || data.path == options.forceReturn;
//  console.log( 'done = ' + done );
  if (!done) { // Not done yet, so show new page in new popups.
    Drupal.popups.removeLoading();
    Drupal.popups.openContent(data.title, data.messages + data.content, options);
  }
  else { // Done, so show messages in dialog and embed the results in the original page.
    if (data.messages.length) {
      Drupal.popups.message(data.messages);
      if (!Drupal.settings.popups.popupFinalMessage) {
        setTimeout(Drupal.popups.close, 2500); // Autoclose the message box in 2.5 seconds.
      }

      // Insert the message into the page above the content.
      // Might not be the standard spot, but it is the easiest to find.
      var $next = $(Drupal.settings.popups.defaultTargetSelector);
      $next.parent().find('div.messages').remove(); // Remove the current messages.
      $next.before(data.messages);
    }
        
    // Update the content area (defined by 'targetSelector').
    if (!options.noReload) { 
      if (isset(options.targetSelectors)) { // Pick and choose what returned content goes where.
        jQuery.each(options.targetSelectors, function(t_new, t_old) {
          if(!isNaN(t_new)) {
            t_new = t_old; // handle case where targetSelectors is an array, not a hash.
          }
          // inject the untrimmed new content into the page, but hidden - ugly hack!
          $('body').prepend('<div id="popups-temp" style="display:none">'+ data.content.replace(/\n/g, '') + '</div>');
          var new_content = $(t_new).html();
          $('#popups-temp').remove();
          var $c = $(t_old).html(new_content); // Inject the trimmed new content into the original page.
          Drupal.popups.attachBehaviors($c, options);
        });
      }
      else { // Put the entire new content into default content area.
        $c = $(Drupal.settings.popups.defaultTargetSelector).html(data.content);
        Drupal.popups.attachBehaviors($c, options);
      }
    }
    
    // Update the title of the page.
    if (isset(options.titleSelectors)) {
      jQuery.each(options.titleSelectors, function() {
        $(''+this).html(data.title);
      });
    }
        
/*        if (!options.noReload) { 
          if (options.targetSelector) { // Pick and choose what returned content goes where.
//            console.log(options.targetSelector);
            for ( var t_new in options.targetSelector ) { // Multple target selector pairs
              var new_content = $(t_new, data.content);
              t_old = options.targetSelector[t_new]
//              console.log(t_old);
              // Update the original page.      
              var $c = $(t_old).html(new_content); // Inject the new content into the page.
              Drupal.popups.attachBehaviors($c, options);
            }
          }
          else { // Put the entire new content into default content area.
            var new_content = data.content;
            var $c = $(Drupal.settings.popups.defaultTargetSelector).html(new_content); // Inject the new content into the page.
            Drupal.popups.attachBehaviors($c, options);                    
          }
        }
        
        // Update the title of the page.
        if (options.updateTitle) {
          $(Drupal.settings.popups.defaultTitleSelector).html(data.title);
          document.title = data.title; // Also update the browser page title (TODO: include site name?).
        }
*/                
    // Done with changes to the original page, remove effects.
    Drupal.popups.removeLoading();
    if (!data.messages.length) { 
      // If there is not a messages popups remove the overlay.
      Drupal.popups.removeOverlay();
    }
  }  // End of updating original page.
}; 

/**
 * Submit the page and reload the results, before popping up the real dialog.
 *
 * @param element
 *   Element that was clicked to open the popups.
 * @param options
 *   Hash of options controlling how the popups interacts with the underlying page.
 */
 
Drupal.popups.savePage = function(element, options) {
  var target = Drupal.settings.popups.defaultTargetSelector;
  var $form = $('form', target);
  var ajaxOptions = {
    dataType: 'json',
    beforeSend: Drupal.popups.beforeSend,
    before: Drupal.popups.beforeSubmit,   
    success: function(response, status) { 
      // Sync up the current page contents with the submit.
      var $c = $(target).html(response.content); // Inject the new content into the page.
      Drupal.popups.attachBehaviors($c, options);
      // The form has been saved, the page reloaded, now safe to show the link in a popup.
      Drupal.popups.openPath(element, options); 
    } 
  };
  $form.ajaxSubmit(ajaxOptions); // Submit the form. 
};

/**
 * Missing Drupal behaviors
 */
Drupal.popups.collapsibleBehavior = function($context) {
//  console.log("collapsibleBehavior");

  $('fieldset.collapsible > legend', $context).each(function() {
    var fieldset = $(this.parentNode);
    // Expand if there are errors inside
    if ($('input.error, textarea.error, select.error', fieldset).size() > 0) {
      fieldset.removeClass('collapsed');
    }

    // Turn the legend into a clickable link and wrap the contents of the fieldset
    // in a div for easier animation
    var text = this.innerHTML;
    $(this).empty().append($('<a href="#">'+ text +'</a>').click(function() {
      var fieldset = $(this).parents('fieldset:first')[0];
      // Don't animate multiple times
      if (!fieldset.animating) {
        fieldset.animating = true;
        Drupal.toggleFieldset(fieldset);
      }
      return false;
    })).after($('<div class="fieldset-wrapper"></div>').append(fieldset.children(':not(legend)')));
  });
};


if (Drupal.jsEnabled) {
  $(document).ready(function() {
    Drupal.popups.behavior($('body'));
  });
}




