changeset 1:4215c43e74eb

Popups: Mise à jour en version alpha6
author Franck Deroche <franck@defr.org>
date Fri, 31 Dec 2010 13:44:00 +0100
parents 76f9b43738f2
children 5efa741592f9
files API.txt CHANGELOG.txt README.txt popups.api.php popups.info popups.install popups.js popups.module popups_admin.info popups_test.info popups_test.module skins/facebook/facebook.js
diffstat 12 files changed, 396 insertions(+), 341 deletions(-) [+]
line wrap: on
line diff
--- a/API.txt	Fri Dec 31 13:41:08 2010 +0100
+++ b/API.txt	Fri Dec 31 13:44:00 2010 +0100
@@ -1,28 +1,28 @@
-As well as attaching popup behavior to links, 
+As well as attaching popup behavior to links,
 Popups API provides javascript function for creating in-window popup messages.
 
 Popups.message(title, message)
   Produces a simple modal box with the title, message and "OK", "Cancel" buttons.
-  
+
 Popups.open(title, body, buttons, width)
   More powerful, allows you to specify what the buttons are and what they do.
   buttons is a hash of hash, with button title and function.
   * Example:
-  Drupal.popups.open( 
-    Drupal.t('Warning: Please Confirm'), 
+  Drupal.popups.open(
+    Drupal.t('Warning: Please Confirm'),
     Drupal.t("There are unsaved changes on this page, which you will lose if you continue."),
-    { 
+    {
       'popup_save': {
-        title: Drupal.t('Save Changes'), 
+        title: Drupal.t('Save Changes'),
         func: function(){Drupal.popups.savePage(element, options);}
       },
       'popup_submit': {
-        title: Drupal.t('Continue'), 
+        title: Drupal.t('Continue'),
         func: function(){Drupal.popups.removePopup(); Drupal.popups.openPath(element, options);}
       },
       'popup_cancel': {
         title: Drupal.t('Cancel'), func: Drupal.popups.close;
-      } 
+      }
     }
   );
 
@@ -34,4 +34,3 @@
  *   Hash of options controlling how the popups interacts with the underlying page.
  * @param parent
  *   If path is being opened from inside another popup, that popup is the parent.
-  
--- a/CHANGELOG.txt	Fri Dec 31 13:41:08 2010 +0100
+++ b/CHANGELOG.txt	Fri Dec 31 13:44:00 2010 +0100
@@ -1,11 +1,15 @@
+6.x--2-0-ALPHA6
+Bug Fixes
+ * Don't show the drupal_set_message in a popup, unless it is the bottom of the stack.
+
 6.x--2-0-ALPHA5
 Features
  * New options and options system.
  ** Added updateMethod, updateSource, onUpdate, doneTest, skipDirtyCheck, and hijackDestination.
  ** Removed noUpdate, reloadOnUpdate, forceReturn, nonModal and afterSubmit.
  ** Default options are declared in popups.js
- ** Options in on-popups-option attribute now override default and hook options, instead of replacing them. 
- * Popups.addedJS => Keeping track of JIT loaded JS files, so they are not reloaded. 
+ ** Options in on-popups-option attribute now override default and hook options, instead of replacing them.
+ * Popups.addedJS => Keeping track of JIT loaded JS files, so they are not reloaded.
 Bug Fixes
  * Fixed tests #7 & #8.
  * Fixing :input highlight in basic.css.
@@ -23,9 +27,9 @@
 Todo
  * Improve Popups.activeLayerIsEdited
  * Recapture the focus on popup if user tabs away.
- 
+
 6.x--2-0-ALPHA4
-Features  
+Features
  * Broadcast "Popups Open Path Done" event.
  * Huge change - Popup Stacking now works. Can have multiple Popups in the dom.
  ** Skins change most ids to classes.
@@ -38,7 +42,7 @@
 Bug Fixes
  * Removing the jit css files on popups close.
 Other
- * Removing additionalJavascript, additionalCSS and additionalJavascriptSettings. 
+ * Removing additionalJavascript, additionalCSS and additionalJavascriptSettings.
 
 6.x--2-0-ALPHA2
 New Features
@@ -49,7 +53,7 @@
  * Inline scripts need more testing:
  ** Should inline scripts be called before or after popup content is loaded?
  *** Poll wants to go after
- ** Should already loaded inlines be executed again? 
+ ** Should already loaded inlines be executed again?
 Todo
  * Can I control order of css adds (modules vs themes)?
  * What about multiple popups - can I flag the js files as already loaded?
@@ -76,7 +80,7 @@
  * http://drupal.org/node/373702 (Rob Loach) - Better wording for auto close messages.
  * Removing hook_theme and popup/save_dialog menu item.
  * http://drupal.org/node/385732 (Rob Loach) - Bugs fixes in refocus().
-Other 
+Other
  * Removed popups-popup.tpl.php - theming html now done in my_theme.js or in a skin.
 
 6.x--1-2
--- a/README.txt	Fri Dec 31 13:41:08 2010 +0100
+++ b/README.txt	Fri Dec 31 13:44:00 2010 +0100
@@ -17,7 +17,9 @@
 
   LIMITATIONS
   ------------------------------------------------------------------------------------  
-  Is this still true? Does not work with tinymce. Unlikely to work with other WYSIWYG's.
+  Does not work with tinymce. Unlikely to work with other WYSIWYG's. (Is this still true?)
+  Conflicts with: 
+    Devel Theme Developer module.
 
   HOW TO USE THE POPUPS API
   ------------------------------------------------------------------------------------  
@@ -34,8 +36,6 @@
   
   // In your module
   popups_add_popups(array('#mylink', '#mylink2=>array('width'=>'200px')));  
-  IMPORTANT: You can only put popups_add_popups in module, NOT in a .tpl file 
-             or the template.php file.
   This is the simplest method if you want to pass in per-link options.
   The first key is a jQuery selector. It should select an 'a' element (unless you 
   are using the 'href' option). See http://docs.jquery.com/Selectors to learn more 
--- a/popups.api.php	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups.api.php	Fri Dec 31 13:44:00 2010 +0100
@@ -1,5 +1,5 @@
 <?php
-// $Id: popups.api.php,v 1.1.4.2 2009/03/05 19:52:48 starbow Exp $
+// $Id: popups.api.php,v 1.1.4.3 2010/12/10 02:09:16 drewish Exp $
 
 /**
  * @file
@@ -12,7 +12,7 @@
 function hook_popups() {
   $popups = array();
   $popups['admin/content/taxonomy'] = array(
-    // Act on the first primary tab. 
+    // Act on the first primary tab.
     'div#tabs-wrapper a:eq(1)',
     // Act on the 2nd column link in the table.
     'table td:nth-child(2) a' => array(
--- a/popups.info	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups.info	Fri Dec 31 13:44:00 2010 +0100
@@ -5,9 +5,9 @@
 core = 6.x
 
 
-; Information added by drupal.org packaging script on 2009-03-21
-version = "6.x-2.0-alpha5"
+; Information added by drupal.org packaging script on 2010-12-10
+version = "6.x-2.0-alpha6"
 core = "6.x"
 project = "popups"
-datestamp = "1237597273"
+datestamp = "1292011844"
 
--- a/popups.install	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups.install	Fri Dec 31 13:44:00 2010 +0100
@@ -1,5 +1,5 @@
 <?php
-// $Id: popups.install,v 1.4.8.2 2009/03/05 19:52:48 starbow Exp $
+// $Id: popups.install,v 1.4.8.3 2010/12/10 02:09:16 drewish Exp $
 
 /**
  * @file
@@ -8,7 +8,7 @@
 /**
  * Implementation of hook_install().
  *
- * Ensures popups runs after everything else, since it short circuits in hook_init. 
+ * Ensures popups runs after everything else, since it short circuits in hook_init.
  */
 function popups_install() {
   db_query("UPDATE {system} SET weight = %d WHERE name = 'popups'", 9999);
--- a/popups.js	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups.js	Fri Dec 31 13:44:00 2010 +0100
@@ -1,4 +1,4 @@
-// $Id: popups.js,v 1.9.8.12 2009/03/21 00:57:15 starbow Exp $
+// $Id: popups.js,v 1.9.8.19 2010/12/10 02:51:17 drewish Exp $
 
 /**
  * Popup Modal Dialog API
@@ -27,7 +27,7 @@
 
 Drupal.behaviors.popups = function(context) {
   Popups.saveSettings();
-  
+
   var $body = $('body');
   if(!$body.hasClass('popups-processed')) {
     $body.addClass('popups-processed');
@@ -37,19 +37,34 @@
       $popit.remove();
       Popups.message($popit.html());
     }
+
+    // Make note of all the CSS and JS on the page so when we load a popup we
+    // don't try to add them a second time.
+    $('link[rel="stylesheet"][href]').each(function(i, v) {
+      Popups.originalCSS[$(this).attr('href').replace(/^(\/.+)\?\w$/, '$1')] = 1;
+    });
+    if (Drupal.settings.popups && Drupal.settings.popups.originalCSS) {
+      $.extend(Popups.originalCSS, Drupal.settings.popups.originalCSS);
+    }
+    $('script[src]').each(function(i, v) {
+      Popups.originalJS[$(this).attr('src').replace(/^(\/.+)\?\w$/, '$1')] = 1;
+    });
+    if (Drupal.settings.popups && Drupal.settings.popups.originalJS) {
+      $.extend(Popups.originalJS, Drupal.settings.popups.originalJS);
+    }
   }
-  
+
   // Add the popups-link-in-dialog behavior to links defined in Drupal.settings.popups.links array.
   // Get these from current Drupal.settings, not Popups.originalSettings, as each page has it's own hooks.
   if (Drupal.settings.popups && Drupal.settings.popups.links) {
-    jQuery.each(Drupal.settings.popups.links, function (link, options) { 
+    jQuery.each(Drupal.settings.popups.links, function (link, options) {
       Popups.attach(context, link, Popups.options(options));
     });
   }
-  
-  Popups.attach(context, '.popups', Popups.options({updateMethod: 'none'}));  
+
+  Popups.attach(context, '.popups', Popups.options({updateMethod: 'none'}));
   Popups.attach(context, '.popups-form', Popups.options({updateMethod: 'ajax'})); // ajax reload.
-  Popups.attach(context, '.popups-form-reload', Popups.options({updateMethod: 'reload'})); // whole page reload. 
+  Popups.attach(context, '.popups-form-reload', Popups.options({updateMethod: 'reload'})); // whole page reload.
   Popups.attach(context, '.popups-form-noupdate', Popups.options({updateMethod: 'none'}));  // no reload at all.
 };
 
@@ -67,9 +82,11 @@
 /**
  * Static variables in the Popups namespace.
  */
-Popups.popupStack = []; 
-Popups.addedCSS = [];
-Popups.addedJS = [];
+Popups.popupStack = [];
+Popups.addedCSS = {};
+Popups.addedJS = {};
+Popups.originalCSS = {};
+Popups.originalJS = {};
 Popups.originalSettings = null; // The initial popup options of the page.
 /**
  * Each popup object gets it's own set of options.
@@ -79,14 +96,15 @@
   doneTest: null, // null, *path*, *regexp*. how do we know when a multiform flow is done?
   updateMethod: 'ajax', // none, ajax, reload, *callback*
   updateSource: 'initial', // initial, final. Only used if updateMethod != none.
-  href: null, 
+  onUpdate: '', // Only used if updateMethod == callback.
+  href: null,
   width: null, // Override the width specified in the css.
   targetSelectors: null, // Hash of jQuery selectors that define the content to be swapped out.
   titleSelectors: null, // Array of jQuery selectors to place the new page title.
   reloadOnError: false, // Force the entire page to reload if the popup href is unaccessable.
-  noMessage: false, // Don't show drupal_set_message messages.   
-  skipDirtyCheck: false, // If true, this popup will not check for edits on the originating page.  
-  hijackDestination: true // Use the destiination param to force a form submit to return to the originating page. 
+  noMessage: false, // Don't show drupal_set_message messages.
+  skipDirtyCheck: false, // If true, this popup will not check for edits on the originating page.
+  hijackDestination: true // Use the destiination param to force a form submit to return to the originating page.
 };
 
 // ***************************************************************************
@@ -98,7 +116,7 @@
  */
 Popups.Popup = function() {
   this.id = 'popups-' + Popups.nextCounter();
-  
+
   // These properties are needed if the popup contains a form that will be ajax submitted.
   this.parent = null; // The popup that spawned this one. If parent is null, this popup was spawned by the original page.
   this.path = null; // If popup is showing content from a url, this is that path.
@@ -126,7 +144,7 @@
 
 /**
  * Create the jQuery wrapped html at the heart of the popup object.
- * 
+ *
  * @param title
  *   String
  * @param body
@@ -141,7 +159,7 @@
 }
 
 /**
- * Hide the popup by pushing it off to the side. 
+ * Hide the popup by pushing it off to the side.
  * Just making it display:none causes flash in FF2.
  */
 Popups.Popup.prototype.hide = function() {
@@ -156,9 +174,9 @@
   return Popups.open(this, title, body, buttons, width);
 };
 
-Popups.Popup.prototype.removePopup = function() { 
+Popups.Popup.prototype.removePopup = function() {
   Popups.removePopup(this);
-}; 
+};
 
 /**
  * Remove everything.
@@ -183,7 +201,7 @@
 
 /**
  * Return a selector that will find target content on the layer that spawned this popup.
- * This is needed for the popup to do ajax updates. 
+ * This is needed for the popup to do ajax updates.
  */
 Popups.Popup.prototype.targetLayerSelector = function() {
   if (this.parent === null) {
@@ -191,38 +209,35 @@
   }
   else {
     return '#' + this.parent.id; // Select content in the parent popup.
-  } 
+  }
 };
 
 /**
  * Determine if we are at an end point of a form flow, or just moving from one popups to another.
- * 
+ *
  * @param path
  *   The path of the page that the form flow has moved to.
- *   This path is relative to the base_path.  
+ *   This path is relative to the base_path.
  *   Ex: node/add/story, not http://localhost/drupal6/node/add/story or drupa6/node/add/story.
  * @return bool
- */ 
+ */
 Popups.Popup.prototype.isDone = function(path) {
-//  console.log("Doing isDone for popup: " + this.id + ", now at " + path );
   var done;
   if (this.options.doneTest) {
     // Test if we are at the path specified by doneTest.
-    done = (path === this.options.doneTest || path.match(this.options.doneTest));    
+    done = (path === this.options.doneTest || path.match(this.options.doneTest));
   }
-  else { 
+  else {
     if (this.parent) {
        // Test if we are back to the parent popup's path.
-      done = (path === this.parent.path);     
-//      console.log("Lookin at parent: " + this.parent.path + ". Done = " + done); 
+      done = (path === this.parent.path);
     }
     else {
        // Test if we are back to the original page's path.
       done = (path === Popups.originalSettings.popups.originalPath);
-//      console.log("Lookin at original page: " + Popups.originalSettings.popups.originalPath + ". Done = " + done); 
     }
-  }; 
-  return done;  
+  };
+  return done;
 };
 
 
@@ -231,7 +246,7 @@
 // ***************************************************************************
 
 /**
- * Test if the param has been set. 
+ * Test if the param has been set.
  * Used to distinguish between a value set to null or false and on not yet unset.
  */
 Popups.isset = function(v) {
@@ -264,19 +279,19 @@
 
 /**
  * Build an options hash from defaults.
- * 
+ *
  * @param overrides
  *   Hash of values to override the defaults.
  */
 Popups.options = function(overrides) {
   var defaults = Popups.defaultOptions;
-  return Popups.overrideOptions(defaults, overrides);  
+  return Popups.overrideOptions(defaults, overrides);
 }
 
 /**
- * Build an options hash.  
+ * Build an options hash.
  * Also maps deprecated options to current options.
- * 
+ *
  * @param defaults
  *   Hash of default values
  * @param overrides
@@ -289,24 +304,24 @@
     if (Popups.isset(overrides[option])) {
       options[option] = overrides[option];
     }
-    else {     
+    else {
       options[option] = defaults[option];
     }
   }
   // Map deprecated options.
   if (overrides['noReload'] || overrides['noUpdate']) {
     options['updateMethod'] = 'none';
-  } 
+  }
   if (overrides['reloadWhenDone']) {
     options['updateMethod'] = 'reload';
-  } 
+  }
   if (overrides['afterSubmit']) {
     options['updateMethod'] = 'callback';
     options['onUpdate'] = overrides['afterSubmit'];
-  } 
+  }
   if (overrides['forceReturn']) {
     options['doneTest'] = overrides['forceReturn'];
-  } 
+  }
   return options;
 }
 
@@ -321,31 +336,30 @@
  *   Hash of options associated with these links.
  */
 Popups.attach = function(context, selector, options) {
-//  console.log(options);
   $(selector, context).not('.popups-processed').each(function() {
-    var $element = $(this);  
-    
-    // Mark the element as processed.    
+    var $element = $(this);
+
+    // Mark the element as processed.
     $element.addClass('popups-processed');
-    
+
     // Append note to link title.
     var title = '';
     if ($element.attr('title')) {
       title = $element.attr('title') + ' ';
     }
     title += Drupal.t('[Popup]');
-    $element.attr('title', title); 
-    
+    $element.attr('title', title);
+
     // Attach the on-click popup behavior to the element.
     $element.click(function(event){
       return Popups.clickPopupElement(this, options);
     });
   });
-};    
+};
 
 /**
  * Respond to click by opening a popup.
- * 
+ *
  * @param element
  *   The element that was clicked.
  * @param options
@@ -353,16 +367,16 @@
  */
 Popups.clickPopupElement = function(element, options) {
   Popups.saveSettings();
-  
+
   // If the element contains a on-popups-options attribute, override default options param.
   if ($(element).attr('on-popups-options')) {
-    var overrides = Drupal.parseJson($(element).attr('on-popups-options')); 
+    var overrides = Drupal.parseJson($(element).attr('on-popups-options'));
     options = Popups.overrideOptions(options, overrides);
   }
-	
+
   // The parent of the new popup is the currently active popup.
   var parent = Popups.activePopup();
-  
+
   // If the option is distructive, check if the page is already modified, and offer to save.
   var willModifyOriginal = !(options.updateMethod === 'none' || options.skipDirtyCheck);
   if (willModifyOriginal && Popups.activeLayerIsEdited()) {
@@ -373,7 +387,7 @@
     // Page is clean, or popup is safe, so just open it.
     Popups.openPath(element, options, parent);
   }
-  return false; 
+  return false;
 };
 
 /**
@@ -383,14 +397,14 @@
 Popups.activeLayerIsEdited = function() {
   var layer = Popups.activePopup();
   var $context = Popups.getLayerContext(layer);
-  // TODO: better test for edited page, maybe capture change event on :inputs.   
-  var edited = $context.find('span.tabledrag-changed').length;  
+  // TODO: better test for edited page, maybe capture change event on :inputs.
+  var edited = $context.find('span.tabledrag-changed').length;
   return edited;
 }
 
 /**
  * Show dialog offering to save form on parent layer.
- * 
+ *
  * @param element
  *   The DOM element that was clicked.
  * @param options
@@ -406,13 +420,13 @@
    'popup_submit': {title: Drupal.t('Continue'), func: function(){popup.removePopup(); Popups.openPath(element, options, parent);}},
    'popup_cancel': {title: Drupal.t('Cancel'), func: function(){popup.close();}}
   };
-  popup.open(Drupal.t('Warning: Please Confirm'), body, buttons);  
+  popup.open(Drupal.t('Warning: Please Confirm'), body, buttons);
 };
 
 /**
  * Generic dialog builder.
  * Adds the newly built popup into the DOM.
- * 
+ *
  * TODO: capture the focus if it tabs out of the dialog.
  *
  * @param popup
@@ -425,17 +439,17 @@
  *   Hash of button parameters.
  * @param width (optional)
  *   Width of new dialog.
- *   
+ *
  * @return popup object
  */
 Popups.open = function(popup, title, body, buttons, width){
   Popups.addOverlay();
-  
+
   if (Popups.activePopup()) {
     // Hiding previously active popup.
     Popups.activePopup().hide();
   }
-  
+
   if (!popup) {
     // Popup object was not handed in, so create a new one.
     popup = new Popups.Popup();
@@ -449,9 +463,9 @@
   if (width) {
     $popup.css('width', width);
   }
-  
+
   // Add the new popup to the DOM.
-  $('body').append($popup); 
+  $('body').append($popup);
 
   // Add button function callbacks.
   if (buttons) {
@@ -459,7 +473,7 @@
       $('#' + id).click(button.func);
     });
   }
-    
+
   // Add the default click-to-close behavior.
   popup.$popupClose().click(function(){
     return Popups.close(popup);
@@ -468,45 +482,45 @@
   Popups.resizeAndCenter(popup);
 
   // Focus on the first input element in the popup window.
-  popup.refocus(); 
-  
+  popup.refocus();
+
   // TODO - this isn't the place for this - should mirror addLoading calls.
   // Remove the loading image.
   Popups.removeLoading();
-   
+
   return popup;
-};  
+};
 
 /**
  * Adjust the popup's height to fit it's content.
  * Move it to be centered on the screen.
  * This undoes the effects of popup.hide().
- * 
+ *
  * @param popup
  */
 Popups.resizeAndCenter = function(popup) {
   var $popup = popup.$popup();
-  
+
   // center on the screen, adding in offsets if the window has been scrolled
-  var popupWidth = $popup.width();  
+  var popupWidth = $popup.width();
   var windowWidth = Popups.windowWidth();
   var left = (windowWidth / 2) - (popupWidth / 2) + Popups.scrollLeft();
-  
+
   // Get popups's height on the page.
   $popup.css('height', 'auto'); // Reset height.
-  var popupHeight = $popup.height(); 
+  var popupHeight = $popup.height();
   $popup.height(popupHeight);
   var windowHeight = Popups.windowHeight();
-   
+
   if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window.
     popupHeight = 0.9 * windowHeight;
     $popup.height(popupHeight);
-  }  
+  }
   var top = (windowHeight / 2) - (popupHeight / 2) + Popups.scrollTop();
 
-  $popup.css('top', top).css('left', left); // Position the popups to be visible. 
+  $popup.css('top', top).css('left', left); // Position the popups to be visible.
 };
-  
+
 
 /**
  *  Create and show a simple popup dialog that functions like the browser's alert box.
@@ -549,7 +563,7 @@
 /*****************************************************************************
  * Appearence Functions (overlay, loading graphic, remove popups)     *********
  *****************************************************************************/
- 
+
 /**
  * Add full page div between the page and the dialog, to make the popup modal.
  */
@@ -560,7 +574,7 @@
     $overlay.css('opacity', '0.4'); // for ie6(?)
     // Doing absolute positioning, so make overlay's size equal the entire body.
     var $doc = $(document);
-    $overlay.width($doc.width()).height($doc.height()); 
+    $overlay.width($doc.width()).height($doc.height());
     $overlay.click(function(){Popups.close();});
     $('body').prepend($overlay);
   }
@@ -596,20 +610,15 @@
 };
 
 // Should I fold this function into Popups.pop?
-Popups.removePopup = function(popup) {  
-//  console.log("Popups.removePopup: " + popup);
+Popups.removePopup = function(popup) {
   if (!Popups.isset(popup)) {
     popup = Popups.activePopup();
   }
   if (popup) {
-//    console.log('removing '+popup.id);
     popup.$popup().remove();
-    Popups.popupStack.splice(Popups.popupStack.indexOf(popup), 1); // Remove popup from stack.  Probably should rework into .pop()
-  }  
-//  else {
-//    console.log("Popups.removePopup - there is no popup to remove.");
-//  }
-}; 
+    Popups.popupStack.splice(jQuery.inArray(popup,Popups.popupStack), 1); // Remove popup from stack.  Probably should rework into .pop()
+  }
+};
 
 /**
  * Remove everything.
@@ -644,7 +653,7 @@
  * Restore the page's original Drupal.settings.
  */
 Popups.restoreSettings = function() {
-  Drupal.settings = Popups.originalSettings;  
+  Drupal.settings = Popups.originalSettings;
 };
 
 /**
@@ -653,9 +662,8 @@
 Popups.restorePage = function() {
   Popups.restoreSettings();
   // Remove the CSS files that were jit loaded for popup.
-  for (var i in Popups.addedCSS) {
-    var link = Popups.addedCSS[i];
-    $('link[href='+ $(link).attr('href') + ']').remove();
+  for (var i in Popups.addedCSS) if (Popups.addedCSS.hasOwnProperty(i)) {
+    $('link[href='+ Popups.addedCSS[i] + ']').remove();
   }
   Popups.addedCSS = [];
 };
@@ -684,7 +692,7 @@
  * Fixes jQuery & Opera bug - http://drupal.org/node/366093
  */
 Popups.windowHeight = function() {
-  if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { 
+  if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") {
     return document.documentElement.clientHeight;
   }
   return $(window).height();
@@ -695,7 +703,7 @@
  * Fixes jQuery & Opera bug - http://drupal.org/node/366093
  */
 Popups.windowWidth = function() {
-  if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { 
+  if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") {
     return document.documentElement.clientWidth;
   }
   return $(window).width();
@@ -720,13 +728,14 @@
  */
 Popups.addCSS = function(css) {
   Popups.addedCSS = [];
-  for (var type in css) {
-    for (var file in css[type]) {
+  for (var type in css) if (css.hasOwnProperty(type)) {
+    for (var file in css[type]) if (css[type].hasOwnProperty(file)) {
       var link = css[type][file];
+      var href = $(link).attr('href');
       // Does the page already contain this stylesheet?
-      if (!$('link[href='+ $(link).attr('href') + ']').length) {
+      if (!Popups.originalCSS[href.replace(/^(\/.+)\?\w$/, '$1')] && !Popups.addedCSS[href]) {
         $('head').append(link);
-        Popups.addedCSS.push(link); // Keep a list, so we can remove them later.
+        Popups.addedCSS[href] = 1; // Keep a list, so we can remove them later.
       }
     }
   }
@@ -739,14 +748,29 @@
   // Parse the json info about the new context.
   var scripts = [];
   var inlines = [];
-  for (var type in js) {
+  var src;
+  for (var type in js) if (js.hasOwnProperty(type)) {
     if (type != 'setting') {
-      for (var file in js[type]) {
+      for (var file in js[type]) if (js[type].hasOwnProperty(file)) {
         if (type == 'inline') {
           inlines.push($(js[type][file]).text());
         }
         else {
-          scripts.push($(js[type][file]).attr('src'));
+          src = $(js[type][file]).attr('src');
+          if (!Popups.originalJS[src.replace(/^(\/.+)\?\w$/, '$1')] && !Popups.addedJS[src]) {
+            // Get the script from the server and execute it.
+            $.ajax({
+              type: 'GET',
+              url: src,
+              dataType: 'script',
+              async : false,
+              success: function(script) {
+                eval(script);
+              }
+            });
+            // Mark the js as added to the underlying page.
+            Popups.addedJS[src] = 1;
+          }
         }
       }
     }
@@ -754,26 +778,6 @@
 
   // Add new JS settings to the page, needed for #ahah properties to work.
   Drupal.settings = js.setting;
-//  console.log('js.setting...');
-//  console.log(js.setting);
-
-  for (var i in scripts) {
-    var src = scripts[i];
-    if (!$('script[src='+ src + ']').length && !Popups.addedJS[src]) {
-      // Get the script from the server and execute it.
-      $.ajax({ 
-        type: 'GET',
-        url: src,
-        dataType: 'script',
-        async : false,
-        success: function(script) {
-          eval(script);
-        }
-      });
-      // Mark the js as added to the underlying page.
-      Popups.addedJS[src] = true;
-    }
-  }
 
   return inlines;
 };
@@ -781,7 +785,7 @@
 /**
  * Execute the jit loaded inline scripts.
  * Q: Do we want to re-excute the ones already in the page?
- * 
+ *
  * @param inlines
  *   Array of inline scripts.
  */
@@ -789,9 +793,9 @@
   // Load the inlines into the page.
   for (var n in inlines) {
     // If the script is not already in the page, execute it.
-    if (!$('script:not([src]):contains(' + inlines[n] + ')').length) {
+    //if (!$('script:not([src]):contains(' + inlines[n] + ')').length) {
       eval(inlines[n]);
-    }
+    //}
   }
 };
 
@@ -827,31 +831,28 @@
 
   // Let the user know something is happening.
   $('body').css("cursor", "wait");
-  
+
   // TODO - get nonmodal working.
   if (!options.nonModal) {
-    Popups.addOverlay(); 
+    Popups.addOverlay();
   }
   Popups.addLoading();
-  
+
   var href = options.href ? options.href : element.href;
   $(document).trigger('popups_open_path', [element, href]); // Broadcast Popup Open Path event.
-  
-  var params = {}; 
+
+  var params = {};
   // Force the popups to return back to the orignal page when forms are done, unless hijackDestination option is set to FALSE.
-  if (options.hijackDestination) { 
+  if (options.hijackDestination) {
     var returnPath;
     if (parent) {
       returnPath = parent.path;
-//      console.log('Popup parent is ...');
-//      console.log(parent);
     }
     else { // No parent, so bring flow back to original page.
       returnPath = Popups.originalSettings.popups.originalPath;
-    }    
+    }
     href = href.replace(/destination=[^;&]*[;&]?/, ''); // Strip out any existing destination param.
-//    console.log("Hijacking destination to " + returnPath);
-    params.destination = returnPath; // Set the destination to return to the parent's path.    
+    params.destination = returnPath; // Set the destination to return to the parent's path.
   }
 
   var ajaxOptions = {
@@ -859,17 +860,17 @@
     dataType: 'json',
     data: params,
     beforeSend: Popups.beforeSend,
-    success: function(json) { 
+    success: function(json) {
       // Add additional CSS to the page.
       Popups.addCSS(json.css);
       var inlines = Popups.addJS(json.js);
       var popup = Popups.openPathContent(json.path, json.title, json.messages + json.content, element, options, parent);
-      Popups.addInlineJS(inlines);   
+      Popups.addInlineJS(inlines);
       // Broadcast an event that the path was opened.
-      $(document).trigger('popups_open_path_done', [element, href, popup]);  
+      $(document).trigger('popups_open_path_done', [element, href, popup]);
     },
     complete: function() {
-      $('body').css("cursor", "auto"); // Return the cursor to normal state.      
+      $('body').css("cursor", "auto"); // Return the cursor to normal state.
     }
   };
 
@@ -877,7 +878,7 @@
   if (options.reloadOnError) {
     ajaxOptions.error = function() {
       location.reload(); // Reload on error. Is this working?
-    };    
+    };
   }
   else {
     ajaxOptions.error = function() {
@@ -885,8 +886,8 @@
     };
   }
   $.ajax(ajaxOptions);
-        
-  return false;         
+
+  return false;
 };
 
 /**
@@ -897,24 +898,23 @@
  * @param content
  *   HTML to show in the popups.
  * @param element
- *   A DOM object containing the element that was clicked to initiate the popup. 
+ *   A DOM object containing the element that was clicked to initiate the popup.
  * @param options
  *   Hash of options controlling how the popups interacts with the underlying page.
  * @param parent
- *   Spawning popup, or null if spawned from original page. 
+ *   Spawning popup, or null if spawned from original page.
  */
-Popups.openPathContent = function(path, title, content, element, options, parent) {  
+Popups.openPathContent = function(path, title, content, element, options, parent) {
   var popup = new Popups.Popup();
-  Popups.open(popup, title, content, null, options.width); 
+  Popups.open(popup, title, content, null, options.width);
 
-  // Set properties on new popup.  
+  // Set properties on new popup.
   popup.parent = parent;
   popup.path = path;
-//  console.log("Setting popup " + popup.id + " originalPath to " + path);
   popup.options = options;
   popup.element = element;
 
-  // Add behaviors to content in popups. 
+  // Add behaviors to content in popups.
   delete Drupal.behaviors.tableHeader; // Work-around for bug in tableheader.js (http://drupal.org/node/234377)
   delete Drupal.behaviors.teaser; // Work-around for bug in teaser.js (sigh).
   Drupal.attachBehaviors(popup.$popupBody());
@@ -924,8 +924,8 @@
   // If the popups contains a form, capture submits.
   var $form = $('form', popup.$popupBody());
   if ($form.length) {
-    $form.ajaxForm({   
-      dataType: 'json',   
+    $form.ajaxForm({
+      dataType: 'json',
       beforeSubmit: Popups.beforeSubmit,
       beforeSend: Popups.beforeSend,
       success: function(json, status) {
@@ -943,13 +943,13 @@
  * The form in the popups was successfully submitted
  * Update the originating page.
  * Show any messages in a popups.
- * 
+ *
  * @param popup
  *   The popup object that contained the form that was just submitted.
  * @param data
  *   JSON object from server with status of form submission.
  */
-Popups.formSuccess = function(popup, data) {    
+Popups.formSuccess = function(popup, data) {
   // Determine if we are at an end point, or just moving from one popups to another.
   var done = popup.isDone(data.path);
   if (!done) { // Not done yet, so show new page in new popups.
@@ -958,7 +958,7 @@
   }
   else { // We are done with popup flow.
     // Execute the onUpdate callback if available.
-    if (popup.options.updateMethod === 'callback' && popup.options.onUpdate) { 
+    if (popup.options.updateMethod === 'callback' && popup.options.onUpdate) {
       var result = eval(popup.options.onUpdate +'(data, popup.options, popup.element)');
       if (result === false) { // Give onUpdate callback a chance to skip normal processing.
         return;
@@ -970,19 +970,27 @@
         location.href = Drupal.settings.basePath + data.path; // TODO: Need to test this.
       }
       else { // Reload originating page.
-        location.reload(); 
+        location.reload();
       }
     }
     else { // Normal, targeted ajax, reload behavior.
+      var showingMessagePopup = false;
       // Show messages in dialog and embed the results in the original page.
-      var showMessage = data.messages.length && !popup.options.noMessage;
-      if (showMessage) {
-        var messagePopup = Popups.message(data.messages); // Popup message.
-        if (Popups.originalSettings.popups.autoCloseFinalMessage) {
-          setTimeout(function(){Popups.close(messagePopup);}, 2500); // Autoclose the message box in 2.5 seconds.
+      // TODO - should seperate these two functions.
+//      var showMessage = data.messages.length && !popup.options.noMessage;
+      if (data.messages.length) {
+        // If we just dismissed the last popup dialog.
+        if (!Popups.activePopup() && !popup.options.noMessage) {
+          // Show drupal_set_message in message popup.
+          var messagePopup = Popups.message(data.messages);
+          if (Popups.originalSettings.popups.autoCloseFinalMessage) {
+            setTimeout(function(){Popups.close(messagePopup);}, 2500); // Autoclose the message box in 2.5 seconds.
+          }
+          showingMessagePopup = true;
         }
-  
-        // Insert the message into the page above the content.
+
+
+        // Insert the message into the parent layer, above the content.
         // Might not be the standard spot, but it is the easiest to find.
         var $next;
         if (popup.targetLayerSelector() === 'body') {
@@ -994,21 +1002,18 @@
         $next.parent().find('div.messages').remove(); // Remove the existing messages.
         $next.before(data.messages); // Insert new messages.
       }
-          
+
       // Update the content area (defined by 'targetSelectors').
-      if (popup.options.updateMethod !== 'none') { 
+      if (popup.options.updateMethod !== 'none') {
         Popups.testContentSelector(); // Kick up warning message if selector is bad.
 
-        Popups.restoreSettings(); // Need to restore original Drupal.settings.popups.links before running attachBehaviors.  This probably has CSS side effects!        
+        Popups.restoreSettings(); // Need to restore original Drupal.settings.popups.links before running attachBehaviors.  This probably has CSS side effects!
         if (popup.options.targetSelectors) { // Pick and choose what returned content goes where.
           jQuery.each(popup.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.
             }
-//            console.log("Updating target " + t_old + ' with ' + t_new);
             var new_content = $(t_new, data.content);
-//            console.log("new content... ");
-//            console.log(new_content);
             var $c = $(popup.targetLayerSelector()).find(t_old).html(new_content); // Inject the new content into the original page.
 
             Drupal.attachBehaviors($c);
@@ -1016,31 +1021,32 @@
         }
         else { // Put the entire new content into default content area.
           var $c = $(popup.targetLayerSelector()).find(Popups.originalSettings.popups.defaultTargetSelector).html(data.content);
-//          console.log("updating entire content area.")
-          Drupal.attachBehaviors($c);                    
+          Drupal.attachBehaviors($c);
         }
       }
-      
+
       // Update the title of the page.
       if (popup.options.titleSelectors) {
         jQuery.each(popup.options.titleSelectors, function() {
           $(''+this).html(data.title);
         });
       }
-              
+
       // Done with changes to the original page, remove effects.
       Popups.removeLoading();
-      if (!showMessage) { 
-        // If there is not a messages popups, close current layer.
-        Popups.close();
+      if (!showingMessagePopup) {
+        // If there is not a messages popups, pop the stack.
+        // Sending in null to Popups.close reveales the next popup in the stack.
+        // If the stack is empty, it will remove the overlay.
+        Popups.close(null);
       }
     }
-    
+
     // Broadcast an event that popup form was done and successful.
     $(document).trigger('popups_form_success', [popup]);
-    
+
   }  // End of updating spawning layer.
-}; 
+};
 
 
 /**
@@ -1048,7 +1054,7 @@
  * @param layer
  *   Either a popup, or null to signify the original page.
  */
-Popups.getLayerContext = function(layer) {  
+Popups.getLayerContext = function(layer) {
   var $context;
   if (!layer) {
     $context = $('body').find(Popups.originalSettings.popups.defaultTargetSelector);
@@ -1067,24 +1073,24 @@
  * @param options
  *   Hash of options controlling how the popups interacts with the underlying page.
  * @param layer
- *   Popup with form to save, or null if form is on original page. 
+ *   Popup with form to save, or null if form is on original page.
  */
 Popups.saveFormOnLayer = function(element, options, layer) {
   var $context = Popups.getLayerContext(layer);
   var $form = $context.find('form');
   var ajaxOptions = {
     dataType: 'json',
-    beforeSubmit: Popups.beforeSubmit,   
+    beforeSubmit: Popups.beforeSubmit,
     beforeSend: Popups.beforeSend,
-    success: function(response, status) { 
+    success: function(response, status) {
       // Sync up the current page contents with the submit.
       var $c = $context.html(response.content); // Inject the new content into the page.
       Drupal.attachBehaviors($c);
       // The form has been saved, the page reloaded, now safe to show the triggering link in a popup.
-      Popups.openPath(element, options, layer); 
-    } 
+      Popups.openPath(element, options, layer);
+    }
   };
-  $form.ajaxSubmit(ajaxOptions); // Submit the form. 
+  $form.ajaxSubmit(ajaxOptions); // Submit the form.
 };
 
 /**
@@ -1102,7 +1108,7 @@
     else if (hits > 1) {
       msg += Drupal.t('There are multiple elements that match: ') + '"' + target + '"\n';
     }
-    msg += Drupal.t('Go to admin/build/themes/settings, select your theme, and edit the "Content Selector" field'); 
+    msg += Drupal.t('Go to admin/build/themes/settings, select your theme, and edit the "Content Selector" field');
     alert(msg);
   }
 };
@@ -1130,14 +1136,14 @@
 Drupal.theme.prototype.popupDialog = function(popupId, title, body, buttons) {
   var template = Drupal.theme('popupTemplate', popupId);
   var popups = template.replace('%title', title).replace('%body', body);
-  
+
   var themedButtons = '';
   if (buttons) {
-    jQuery.each(buttons, function (id, button) { 
+    jQuery.each(buttons, function (id, button) {
       themedButtons += Drupal.theme('popupButton', button.title, id);
-    });  
-  }  
-  popups = popups.replace('%buttons', themedButtons);  
+    });
+  }
+  popups = popups.replace('%buttons', themedButtons);
   return popups;
 };
 
@@ -1155,4 +1161,3 @@
   template += '</div>';
   return template;
 };
-
--- a/popups.module	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups.module	Fri Dec 31 13:44:00 2010 +0100
@@ -1,9 +1,9 @@
 <?php
-// $Id: popups.module,v 1.11.8.10 2009/03/21 00:57:15 starbow Exp $
+// $Id: popups.module,v 1.11.8.14 2010/12/10 19:58:10 drewish Exp $
 
 /**
  * @file
- * This module provides a hook_popups for links to be openned in an Ajax Popup Modal Dialog. 
+ * This module provides a hook_popups for links to be openned in an Ajax Popup Modal Dialog.
  */
 
 
@@ -16,8 +16,8 @@
  *
  * @return array of new menu items.
  */
-function popups_menu() { 
-  
+function popups_menu() {
+
   // Admin Settings.
   $items['admin/settings/popups'] = array(
     'page callback' => 'drupal_get_form',
@@ -25,17 +25,17 @@
     'title' => 'Popups',
     'access arguments' => array('administer site configuration'),
     'description' => 'Configure the page-in-a-dialog behavior.',
-  ); 
-  
+  );
+
   return $items;
 }
 
 /**
  * Implementation of hook_init().
- * 
+ *
  * Look at the page path and see if popup behavior has been requested for any links in this page.
  */
-function popups_init() {  
+function popups_init() {
   $popups = popups_get_popups();
 
   if (variable_get('popups_always_scan', 0)) {
@@ -49,13 +49,13 @@
     elseif (strpos($path, '*') !== FALSE && drupal_match_path($_GET['q'], $path)) {
       popups_add_popups($popup_config);
     }
-  }  
-  
+  }
+
   $render_mode = '';
   if (isset($_SERVER['HTTP_X_DRUPAL_RENDER_MODE'])) {
     $render_mode = $_SERVER['HTTP_X_DRUPAL_RENDER_MODE'];
   }
-  
+
   // Check and see if the page_override param is in the URL.
   // Note - the magic happens here.
   // Need to cache the page_override flag in the session, so it will effect
@@ -68,39 +68,38 @@
   if (isset($_SESSION['page_override'])) {
     // This call will not return on form submission.
     $content = menu_execute_active_handler();
-    
-    // The call did return, so it wasn't a form request, 
+
+    // The call did return, so it wasn't a form request,
     // so we are returning a result, so clear the session flag.
     $override = $_SESSION['page_override'];
     unset($_SESSION['page_override']);
-       
+
     // Menu status constants are integers; page content is a string.
     if (isset($content) && !is_int($content) && isset($override)) {
-      print popups_render_as_json($content); 
+      print popups_render_as_json($content);
       exit;  // Do not continue processing request in index.html.
-    }    
+    }
   }
-  
+
 }
 
 /**
  * Implementation of hook_form_alter().
- * 
+ *
  * Look at the form_id and see if popup behavior has been requested for any links in this form.
  *
  * @param form_array $form
  * @param array $form_state
- * @param str $form_id: 
+ * @param str $form_id:
  */
 function popups_form_alter(&$form, $form_state, $form_id) {
   // Add popup behavior to the form if requested.
-//  dsm($form_id);
   $popups = popups_get_popups();
   if (isset($popups[$form_id])) {
     popups_add_popups($popups[$form_id]);
-  } 
+  }
 
-  // Alter the theme configuration pages, to add a per-theme-content selector. 
+  // Alter the theme configuration pages, to add a per-theme-content selector.
   $theme = arg(4);
   if ($form_id == 'system_theme_settings' && $theme) {
     $form['popups'] = array(
@@ -113,11 +112,11 @@
       '#title' => t('Content Selector'),
       '#default_value' => variable_get('popups_'. $theme .'_content_selector', _popups_default_content_selector()),
       '#description' => t("jQuery selector to define the page's content area on this theme."),
-    ); 
+    );
     $form['popups']['popups_theme'] = array(
       '#type' => 'hidden',
       '#value' => $theme,
-    ); 
+    );
     $form['#submit'][] = 'popups_theme_settings_form_submit';
   }
 }
@@ -132,7 +131,11 @@
  * @param $content: themed html.
  * @return $content in a json wrapper with metadata.
  */
-function popups_render_as_json($content) { 
+function popups_render_as_json($content) {
+  // Call theme_page so modules like jquery_update can do their thing. We don't
+  // really care about the mark up though.
+  $ignore = theme('page', $content);
+
   $path = $_GET['q']; // Get current path from params.
   return drupal_json(array(
     'title' => drupal_get_title(),
@@ -140,7 +143,7 @@
     'path' => $path,
     'content' => $content,
     'js' => popups_get_js(),
-    'css' => popups_get_css(), 
+    'css' => popups_get_css(),
   ));
 }
 
@@ -150,7 +153,7 @@
 function popups_get_js() {
   $js = array_merge_recursive(drupal_add_js(), drupal_add_js(NULL, NULL, 'footer'));
   $query_string = '?'. substr(variable_get('css_js_query_string', '0'), 0, 1);
-  
+
   $popup_js = array();
 
   foreach ($js as $type => $data) {
@@ -173,9 +176,21 @@
     }
   }
 
-  // A special exception, never include the popups settings in the JS array.
-  // ???
-//  unset($popup_js['setting']['popups']);
+  unset($popup_js['core']['misc/jquery.js']);
+  unset($popup_js['core']['misc/drupal.js']);
+
+  if (module_exists('jquery_update')) {
+    foreach (jquery_update_get_replacements() as $type => $replacements) {
+      foreach ($replacements as $find => $replace) {
+        if (isset($popup_js[$type][$find])) {
+          // Create a new entry for the replacement file, and unset the original one.
+          $replace = JQUERY_UPDATE_REPLACE_PATH .'/'. $replace;
+          //$popup_js[$type][$replace] = str_replace($find, $replace, $popup_js[$type][$find]);
+          unset($popup_js[$type][$find]);
+        }
+      }
+    }
+  }
 
   return $popup_js;
 }
@@ -233,12 +248,12 @@
 /**
  * Define hook_popups().
  * Build the list of popup rules from all modules that implement hook_popups.
- * 
+ *
  * Retrieves the list of popup rules from all modules that implement hook_popups.
  *
  * @param $reset
  *   (optional) If set to TRUE, forces the popup rule cache to reset.
- * 
+ *
  */
 function popups_get_popups($reset = FALSE) {
   static $popups = NULL;
@@ -247,37 +262,37 @@
     if (!$reset && ($cache = cache_get('popups:popups')) && !empty($cache->data)) {
       $popups = $cache->data;
     }
-    else { 
+    else {
       // Call all hook_popups and cache results.
       $popups = module_invoke_all('popups');
-      
+
       // Invoke hook_popups_alter() to allow altering the default popups registry.
       drupal_alter('popups', $popups);
 
-      // Save the popup registry in the cache.      
+      // Save the popup registry in the cache.
       cache_set('popups:popups', $popups);
-    }  
+    }
   }
   return $popups;
 }
 
 /**
  * Attach the popup behavior to the page.
- * 
- * The default behavoir of a popup is to open a form that will modify the original page.  
- * The popup submits the form and reloads the original page with the resulting new content. 
+ *
+ * The default behavoir of a popup is to open a form that will modify the original page.
+ * The popup submits the form and reloads the original page with the resulting new content.
  * The popup then replaces the original page's content area with the new copy of that content area.
  *
  * @param array $rules: Array of rules to apply to the page or form, keyed by jQuery link selector.
- *   See README.txt for a listing of the options, and popups_admin.module for examples. 
+ *   See README.txt for a listing of the options, and popups_admin.module for examples.
  */
-function popups_add_popups($rules=NULL) { 
+function popups_add_popups($rules=NULL) {
   static $added = FALSE;
   $settings = array('popups' => array());
-  
+
   if (is_array($rules)) {
     $settings['popups']['links'] = array();
-    foreach ($rules as $popup_selector => $options) { 
+    foreach ($rules as $popup_selector => $options) {
       if (is_array($options)) {
         $settings['popups']['links'][$popup_selector] = $options;
       }
@@ -296,7 +311,7 @@
     if (!$theme) {
       $theme = variable_get('theme_default','none');
     }
-    
+
     drupal_add_js('misc/jquery.form.js');
     drupal_add_css(drupal_get_path('module', 'popups') .'/popups.css');
     drupal_add_js(drupal_get_path('module', 'popups') .'/popups.js');
@@ -312,15 +327,14 @@
       drupal_add_css($skins[$skin]['css']);
       if (isset($skins[$skin]['js'])) {
         drupal_add_js($skins[$skin]['js']);
-      }   
+      }
     }
-        
+
     $default_target_selector = variable_get('popups_'. $theme .'_content_selector', _popups_default_content_selector());
-    
+
     $settings['popups']['originalPath'] = $_GET['q'];
     $settings['popups']['defaultTargetSelector'] = $default_target_selector;
     $settings['popups']['modulePath'] = drupal_get_path('module', 'popups');
-//    $settings['popups']['popupFinalMessage'] = variable_get('popups_popup_final_message', 1);
     $settings['popups']['autoCloseFinalMessage'] = variable_get('popups_autoclose_final_message', 1);
     drupal_add_js( $settings, 'setting' );
     $added = TRUE;
@@ -352,14 +366,14 @@
 
 /**
  * Implementation of hook_popups_skins.
- * 
+ *
  * This hook allows other modules to create additional custom skins for the
  * popups module.
- * 
+ *
  * @return array
  *   An array of key => value pairs suitable for inclusion as the #options in a
- *   select or radios form element. Each key must be the location of at least a 
- *   css file for a popups skin. Optionally can have a js index as well. Each 
+ *   select or radios form element. Each key must be the location of at least a
+ *   css file for a popups skin. Optionally can have a js index as well. Each
  *   value should be the name of the skin.
  */
 function popups_popups_skins() {
@@ -381,7 +395,7 @@
 
 /**
  * Returns the default jQuery content selector as a string.
- * Currently uses the selector for Garland.  
+ * Currently uses the selector for Garland.
  * Sometime in the future I will change this to '#content' or '#content-content'.
  */
 function _popups_default_content_selector() {
@@ -398,7 +412,6 @@
  */
 function popups_admin_settings() {
   popups_add_popups();
-//  drupal_add_css(drupal_get_path('module', 'popups'). '/skins/blue/blue.css'); // temp
   drupal_set_title("Popups Settings");
   $form = array();
 
@@ -416,7 +429,7 @@
   // Retrieve all available skins, forcing the registry to refresh.
   $skins['Unskinned'] = array();
   $skins += popups_skins(TRUE);
-  
+
   $skin_options = drupal_map_assoc(array_keys($skins));
   $form['popups_skins'] = array(
     '#type' => 'fieldset',
@@ -432,13 +445,13 @@
     '#options' => $skin_options,
   );
 
-  
+
   return system_settings_form($form);
 }
 
 /**
  * popups_form_alter adds this submit handler to the theme pages.
- * Set a per-theme jQuery content selector that gets passed into the js settings. 
+ * Set a per-theme jQuery content selector that gets passed into the js settings.
  *
  * @param $form
  * @param $form_state
@@ -449,3 +462,39 @@
   variable_set('popups_'. $theme .'_content_selector', $content_selector);
 }
 
+/**
+ * Implementation of hook_preprocess_hook().
+ *
+ * When CSS or JS aggregation is enabled make a list of the CSS/JS incorporated
+ * in it so we don't re-add it when loading the popup content.
+ */
+function popups_preprocess_page() {
+  $base_path = base_path();
+
+  if (variable_get('preprocess_css', 0)) {
+    $css_on_page = array();
+    foreach (popups_get_css() as $type => $files) {
+      foreach ($files as $path => $html) {
+        $css_on_page[$base_path . $path] = 1;
+      }
+    }
+    $settings['popups']['originalCSS'] = $css_on_page;
+  }
+
+  if (variable_get('preprocess_js', 0)) {
+    $js_on_page = array();
+    $js = popups_get_js();
+    // We don't care about settings or inline css.
+    unset($js['inline'], $js['setting']);
+    foreach ($js as $type => $files) {
+      foreach ($files as $path => $html) {
+        $js_on_page[$base_path . $path] = 1;
+      }
+    }
+    $settings['popups']['originalJS'] = $js_on_page;
+  }
+
+  if (isset($settings)) {
+    drupal_add_js($settings, 'setting');
+  }
+}
--- a/popups_admin.info	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups_admin.info	Fri Dec 31 13:44:00 2010 +0100
@@ -6,9 +6,9 @@
 dependencies[] = popups
 
 
-; Information added by drupal.org packaging script on 2009-03-21
-version = "6.x-2.0-alpha5"
+; Information added by drupal.org packaging script on 2010-12-10
+version = "6.x-2.0-alpha6"
 core = "6.x"
 project = "popups"
-datestamp = "1237597273"
+datestamp = "1292011844"
 
--- a/popups_test.info	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups_test.info	Fri Dec 31 13:44:00 2010 +0100
@@ -6,9 +6,9 @@
 dependencies[] = popups
 
 
-; Information added by drupal.org packaging script on 2009-03-21
-version = "6.x-2.0-alpha5"
+; Information added by drupal.org packaging script on 2010-12-10
+version = "6.x-2.0-alpha6"
 core = "6.x"
 project = "popups"
-datestamp = "1237597273"
+datestamp = "1292011844"
 
--- a/popups_test.module	Fri Dec 31 13:41:08 2010 +0100
+++ b/popups_test.module	Fri Dec 31 13:44:00 2010 +0100
@@ -1,5 +1,5 @@
 <?php
-// $Id: popups_test.module,v 1.1.4.6 2009/03/19 15:53:44 starbow Exp $
+// $Id: popups_test.module,v 1.1.4.7 2010/12/10 02:09:16 drewish Exp $
 
 /**
  * @file
@@ -40,13 +40,13 @@
     'page callback' => '_popups_test_popups_old',
     'type' => MENU_CALLBACK,
     'access callback' => TRUE,
-  );  
+  );
   return $items;
 }
 
 /**
  *  Implementation of hook_popups().
- * 
+ *
  * This implements hook_popups, defined in popups_get_popups.
  * See the comments in popups_add_popups for explination of the options.
  * Adding popup behavior to the core admin pages has been moved to popups_admin.
@@ -54,15 +54,15 @@
  * @return: Array of link selectors to apply popup behavior to.
  *          Keyed by path or form_id.
  */
-function popups_test_popups() {   
+function popups_test_popups() {
   return array(
     'popups/test' => array( // test page.
 //    '*' => array( // test page.
-      '#test-popup' => array( 
+      '#test-popup' => array(
 //        'additionalJavascript' => array('misc/collapse.js'),
 //        'forceReturn' => 'node/add/story',
       ),
-    ),  
+    ),
   );
 }
 
@@ -73,69 +73,69 @@
 function _popups_test_popups() {
   popups_add_popups();
   $output = '<ol id="test-list">';
-  $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response', 
+  $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response',
                array('attributes' => array('class' => 'popups')));
-  $output .= "<li>". l("Pop with options (href override).", 'popups/test/', 
+  $output .= "<li>". l("Pop with options (href override).", 'popups/test/',
                array('attributes' => array('class' => 'popups', 'on-popups-options' => '{href: "test/response"}')));
-  $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response', 
+  $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response',
                array('attributes' => array('class' => 'popups', 'on-popups-options' => '{width: "200px"}')));
   $output .= "<li class=\"popups\" on-popups-options=\"{href: 'test/response'}\">Non-link popup</li>";
   $output .= '<li>'. l("Add Story (hook)", 'node/add/story',
                array( 'attributes' => array('id' => 'test-popup')));
   $output .= '<li>'. l("Add Story (attribute).", 'node/add/story',
                array( 'attributes' => array('class' => 'popups-form')));
-               
-  $output .= '<li>'. l("Change Settings and ajax update entire content area: ", 
+
+  $output .= '<li>'. l("Change Settings and ajax update entire content area: ",
                        'admin/settings/popups',
                        array( 'attributes' => array('class' => 'popups-form'),
                      ));
   $output .= " (Auto Fade checkbox is: " . (variable_get('popups_autoclose_final_message', 1) ? 'on' : 'off') . ')';
 
   $output .= '<li>'. l("Change Settings and ajax update only single target.", 'admin/settings/popups',
-               array( 'attributes' => array('id' => 'reload-target'), 
+               array( 'attributes' => array('id' => 'reload-target'),
                ));
   $output .= "<span id='response2'> (Auto Fade checkbox is: " . (variable_get('popups_autoclose_final_message', 1) ? 'on' : 'off') . ')</span>';
-  popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2'))));   
-      
+  popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2'))));
+
   $output .= '<li>'. l("Change Settings and ajax update multiple targets with data from other page (tricky!).", 'admin/settings/popups',
              array( 'attributes' => array(
                 'id' => 'foo',
                 'class' => 'popups-form',
                 'on-popups-options' => '{targetSelectors: {"#edit-popups-always-scan-wrapper": "#foo", "#edit-popups-popup-final-message-wrapper": "#test-list li:first"}, forceReturn: "admin/settings/popups"}')));
 
-  $output .= '<li>'. l("Change Settings and reload entire page.", 
+  $output .= '<li>'. l("Change Settings and reload entire page.",
                        'admin/settings/popups',
                        array( 'attributes' => array('class' => 'popups-form-reload'),
                      ));
-                     
-  $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response', 
+
+  $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response',
                      array('attributes' => array('id' => 'rule-test')));
-  popups_add_popups(array('#rule-test'=>array('width'=>'300px')));       
-  $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange', 
+  popups_add_popups(array('#rule-test'=>array('width'=>'300px')));
+  $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange',
                      array('attributes' => array('id' => 'title-test')));
-  popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange')));       
+  popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange')));
 
   global $user;
   $output .= "<li>You are user number $user->uid</li>";
   if ($user->uid == 0) {
-    $output .= '<li>'. l("Login and ajax refresh content area.", 'user', 
+    $output .= '<li>'. l("Login and ajax refresh content area.", 'user',
                        array('attributes' => array('class' => 'popups-form')));
-    $output .= '<li>'. l("Login and reload entire page.", 'user', 
-                       array('attributes' => array('class' => 'popups-form-reload')));                   
-    $output .= '<li>'. l("Login and do not reload anything.", 'user', 
-                       array('attributes' => array('class' => 'popups-form-noupdate')));                   
+    $output .= '<li>'. l("Login and reload entire page.", 'user',
+                       array('attributes' => array('class' => 'popups-form-reload')));
+    $output .= '<li>'. l("Login and do not reload anything.", 'user',
+                       array('attributes' => array('class' => 'popups-form-noupdate')));
   }
   else {
-    $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout', 
+    $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout',
                      array('attributes' => array('id' => 'logout')));
   }
   // Need to have the rule outside the else, or it won't get loaded on ajax reload.
-  popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE))); 
+  popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE)));
 
-  $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll', 
+  $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll',
                        array('attributes' => array('class' => 'popups-form')));
-    
-  $output .= "</ol>";                
+
+  $output .= "</ol>";
   return $output;
 }
 
@@ -143,69 +143,69 @@
 //  drupal_set_message('Popup Test Page: If you edit your page.tpl.php to wrap the print $messages in a div with id="popit", this message will popup on page load');
   popups_add_popups();
   $output = '<ul id="test-list">';
-  $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response', 
+  $output .= '<li>'. l("Pop up entire local page.", 'popups/test/response',
                array('attributes' => array('class' => 'popups')));
-  $output .= "<li>". l("Pop with options (href override).", 'popups/test/', 
+  $output .= "<li>". l("Pop with options (href override).", 'popups/test/',
                array('attributes' => array('class' => 'popups', 'on-popups-options' => '{href: "test/response"}')));
-  $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response', 
+  $output .= "<li>". l("Pop with options (width=200px).", 'popups/test/response',
                array('attributes' => array('class' => 'popups', 'on-popups-options' => '{width: "200px"}')));
   $output .= "<li class=\"popups\" on-popups-options=\"{href: 'test/response'}\">Non-link popup</li>";
   $output .= '<li>'. l("Add Story (hook)", 'node/add/story',
                array( 'attributes' => array('id' => 'test-popup')));
   $output .= '<li>'. l("Add Story (attribute).", 'node/add/story',
                array( 'attributes' => array('class' => 'popups-form')));
-               
-  $output .= '<li>'. l("Change Settings and ajax update entire content area: ", 
+
+  $output .= '<li>'. l("Change Settings and ajax update entire content area: ",
                        'admin/settings/popups',
                        array( 'attributes' => array('class' => 'popups-form'),
                      ));
   $output .= " (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')';
 
   $output .= '<li>'. l("Change Settings and ajax update only single target.", 'admin/settings/popups',
-               array( 'attributes' => array('id' => 'reload-target'), 
+               array( 'attributes' => array('id' => 'reload-target'),
                ));
   $output .= "<span id='response2'> (Auto Fade checkbox is: " . (variable_get('popups_popup_final_message', 1) ? 'on' : 'off') . ')</span>';
-  popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2'))));   
-      
+  popups_add_popups(array('#reload-target'=>array('targetSelectors'=>array('#response2'))));
+
   $output .= '<li>'. l("Change Settings and ajax update multiple targets with data from other page (tricky!).", 'admin/settings/popups',
              array( 'attributes' => array(
                 'id' => 'foo',
                 'class' => 'popups-form',
                 'on-popups-options' => '{targetSelectors: {"#edit-popups-always-scan-wrapper": "#foo", "#edit-popups-popup-final-message-wrapper": "#test-list li:first"}, forceReturn: "admin/settings/popups"}')));
 
-  $output .= '<li>'. l("Change Settings and reload entire page.", 
+  $output .= '<li>'. l("Change Settings and reload entire page.",
                        'admin/settings/popups',
                        array( 'attributes' => array('class' => 'popups-form-reload'),
                      ));
-                     
-  $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response', 
+
+  $output .= '<li>'. l("Pop up defined by popups_add_popups rule.", 'popups/test/response',
                      array('attributes' => array('id' => 'rule-test')));
-  popups_add_popups(array('#rule-test'=>array('width'=>'300px')));       
-  $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange', 
+  popups_add_popups(array('#rule-test'=>array('width'=>'300px')));
+  $output .= '<li>'. l('Ajax update just Page Title (only works if you theme uses id="page-title")', 'popups/test/namechange',
                      array('attributes' => array('id' => 'title-test')));
-  popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange')));       
+  popups_add_popups(array('#title-test'=>array('titleSelectors'=>array('#page-title'), 'noUpdate'=> TRUE, 'forceReturn'=>'popups/test/namechange')));
 
   global $user;
   $output .= "<li>You are user number $user->uid</li>";
   if ($user->uid == 0) {
-    $output .= '<li>'. l("Login and ajax refresh content area.", 'user', 
+    $output .= '<li>'. l("Login and ajax refresh content area.", 'user',
                        array('attributes' => array('class' => 'popups-form')));
-    $output .= '<li>'. l("Login and reload entire page.", 'user', 
-                       array('attributes' => array('class' => 'popups-form-reload')));                   
-    $output .= '<li>'. l("Login and do not reload anything.", 'user', 
-                       array('attributes' => array('class' => 'popups-form-noupdate')));                   
+    $output .= '<li>'. l("Login and reload entire page.", 'user',
+                       array('attributes' => array('class' => 'popups-form-reload')));
+    $output .= '<li>'. l("Login and do not reload anything.", 'user',
+                       array('attributes' => array('class' => 'popups-form-noupdate')));
   }
   else {
-    $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout', 
+    $output .= '<li>'. l("Logout (need to surpress warning b/c session is dumped)", 'logout',
                      array('attributes' => array('id' => 'logout')));
   }
   // Need to have the rule outside the else, or it won't get loaded on ajax reload.
-  popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE))); 
+  popups_add_popups(array('#logout'=>array('noUpdate'=>TRUE, 'reloadOnError'=>TRUE)));
 
-  $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll', 
+  $output .= '<li>'. l("Add Poll (test inline)", 'node/add/poll',
                        array('attributes' => array('class' => 'popups-form')));
-    
-  $output .= "</ul>";                
+
+  $output .= "</ul>";
   return $output;
 }
 
@@ -222,6 +222,6 @@
     '#type' => 'submit',
     '#value' => t('Test Name Change'),
   );
-  
+
   return $form;
 }
--- a/skins/facebook/facebook.js	Fri Dec 31 13:41:08 2010 +0100
+++ b/skins/facebook/facebook.js	Fri Dec 31 13:44:00 2010 +0100
@@ -3,7 +3,6 @@
  * Custom theming for the popupsLoading.
  */
 Drupal.theme.popupLoading = function() {
-console.log("Drupal.theme.popupLoading: Facebook");
   var loading;
   loading += '<div id="popups-loading">';
   loading += '  <table>';
@@ -30,7 +29,6 @@
 };
 
 Drupal.theme.popupTemplate = function (popupId) {
-console.log("Drupal.theme.popupTemplate: Facebook");
   var template;
   template += '<div id="' + popupId + '" class ="popups-box">';
   template += '  <table>';