From be1a433c279dd7f4373ef1af4769e693178274d2 Mon Sep 17 00:00:00 2001
From: Earl Miles <merlin@logrus.com>
Date: Tue, 14 Apr 2009 05:24:20 +0000
Subject: [PATCH] More robust AJAX stuff that will eliminate some ugly errors
 plus prevent double clicks on ajax links.

---
 css/ctools.css                          |  10 +++
 css/modal.css                           |   2 +-
 ctools.module                           |   7 ++
 images/no-icon.png                      | Bin 0 -> 574 bytes
 images/status-active.gif                | Bin 0 -> 2196 bytes
 includes/content.inc                    |   7 +-
 js/ajax-responder.js                    | 112 +++++++++++++++---------
 js/modal.js                             |  60 +++++++++----
 plugins/content_types/block/block.inc   |   8 +-
 plugins/content_types/custom/custom.inc |   3 +
 10 files changed, 146 insertions(+), 63 deletions(-)
 create mode 100644 images/no-icon.png
 create mode 100644 images/status-active.gif

diff --git a/css/ctools.css b/css/ctools.css
index 5cf9c5b4..4a2d875d 100644
--- a/css/ctools.css
+++ b/css/ctools.css
@@ -10,3 +10,13 @@
   border: 1px solid #F0C020;
   padding: 1em;
 }
+
+a.ctools-ajaxing {
+  padding-right: 18px !important;
+  background: url(../images/status-active.gif) right center no-repeat;
+}
+
+input.ctools-ajaxing {
+  padding-right: 18px;
+  background: url(../images/status-active.gif) right center no-repeat;
+}
diff --git a/css/modal.css b/css/modal.css
index 40a75258..61cabacb 100644
--- a/css/modal.css
+++ b/css/modal.css
@@ -28,7 +28,7 @@ div.ctools-modal-content .modal-header a {
 }
 
 div.ctools-modal-content .modal-content {
-  padding: 0 1em;
+  padding: 1em 1em 0 1em;
   overflow: auto;
   width: 575px;
   height: 400px;
diff --git a/ctools.module b/ctools.module
index fa41de94..cc5b13d1 100644
--- a/ctools.module
+++ b/ctools.module
@@ -43,6 +43,13 @@ function ctools_add_js($file) {
   drupal_add_js(drupal_get_path('module', 'ctools') . "/js/$file.js");
 }
 
+/**
+ * Implement hook_init to keep our global CSS at the ready.
+ */
+function ctools_init() {
+  ctools_add_css('ctools');
+}
+
 /**
  * Provide a hook passthrough to included files.
  *
diff --git a/images/no-icon.png b/images/no-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..fa78ec179a83428e5b8e247890278cdf91a8cb3e
GIT binary patch
literal 574
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5
z;QX|b^2DN42FH~Aq*MjZ+{E<Mpwz^a%EFVWHb6za0X`wFr45!Je(pYfWm-(COIf{R
zd6V9oHxIsid0$fJW$SEo`f5jcz0Kr#;igtPWlb7C|6e?HweQFOEB9`%zH@8cwJS?s
zew%dq@~pQ%Hop2cr@TdB$^y5t8qc@iSAF=g_1DjDXU|Og@&9sJgYlcUPo^&LIdf&=
zlzD;P!IqytKQF6u{q*bLf@QgT_BMU}ed7QB|3DYT#AfRNDgBZlzhIyU34kGLsl|7o
z)<2#ujv*Ddk}e1fiA|h-osCIX;lgER4h1$v5k@}S28JYoYgZYWeFZLDeaZk772MFU
ztgVerS>S{rGmAj8jfaD?v!i2UYjjvlpQJ*A1Jfmibqf^i?VA_L7&|Z+X1sot(Xnwu
z!w#NRT}4?8j7Jun<r7IrN_zP0*+WK71{Q$;hu~&USJ&1?_t4Opp|QLQ4F)U>OdXEg
zItmI4IG$*KURlh<BH+>B>e|rlEqG%3qu@s@KxgP$`nu(@>FI?n*t0}KS|4Q7%GJhQ
zr!}-TZTjTdv1#K+psr@Qb}IpmMn>t`v&?`hUc4+UFfd-t$f&NazkZvXLjxnjnNaC9
Um!If;0EPpDr>mdKI;Vst09}j(6951J

literal 0
HcmV?d00001

diff --git a/images/status-active.gif b/images/status-active.gif
new file mode 100644
index 0000000000000000000000000000000000000000..207e95c3fa8cc31a89af150ad74059b1667922b6
GIT binary patch
literal 2196
zcmeH{Urbw79LLW&_xASmFQt@HSs}NhO2-Jh1BM+kb4v^B62vmdY!-sIxUi{Y-eKaZ
zd%2gEe>0H6h_VE=!^E(JL`)>X2jVS^Zcfvn5<-k2WvFCNG`ghG7rZ6$WnPVsKJ5GO
zJ8$RvJD>CY{Z5~0cApFxfB|GdPWa6w{k0|AwWK|oJQ2I!Je@i}^Zo0eZod2F_QJwK
zJhi*9v9}~^YcH8hrc$Ymjg76Xt@{st+t|%+?PYgm$u+ybCo8+3&1pZopVPthPs$Sl
z|6c-*eO+r)N4wV(XsWJa2q<^z_?=Wy@>!YdIyWW&Uj-18tONF|3Mu0pM+@E|b#0}^
z!~zi%9q%)3&a(p~G`B1c3*4%%lzk?{ByJ6=pegKss;|dO;n%+FeCW7{V%4V@w<Prd
z%F>$Z{GnR7Ggdfd96mCSRsm(IU3X`eH-@mY!nv5{mPH7adf{@tFd+{D#Z*P7E4Cu(
zNI<&yxF8`-(K~6DmV_bgDJSM6QPSy-`a53zHsK*ro@??84uYGYiss#G335cQ(q<T@
z`^CZLH_nsuwU=5Zb#0}cHj|R+xtu8<;s!)Qci1v(k~|`1?F+irB10NPwE`0tSF2U^
z+6<im-Ww1Hd@dR`k+{&xVS1-gZ9in)bj2<%i#281b&mh}&cO2{Mm<)t3jM`e#IVEf
z3J{GD(1#g123De0)!E_UoF_nTk~awv(p3<=z%wHIKJ2D|V0J_Zci!BO;e4ksj*7ZE
zaK0c;0L<IMq65W=XG<*=46Wqa{SQ<*PK@eny6#~a=BV}<y_imT#W8h0o^#RS&~=>^
z%wp~p0g$crQ*_&{2!a61R3ETvWG(*SZ8O_GR^u5Yc|OD{*}kN}6<BQdLfgxbC<mBp
z`xxY*JbDh(Gfkp~t@6?H=&rUxgG>zL0fe!xt};GOz%hKaYMskC&qRw=<`U&U>^cAo
zLBAqcYczaZ@J3LHlNVx%1c};=4Y#YG7RXW%xDepEe!!I1`hwd%{Td?N=QPn}&`2C(
ze3|@EBBE1Mq|)<VKA;NO$Fur4RVf(Xkt2F^h74Rup!Z4$EV<S^2>`TYFdd2uA0l<j
zqjX|tdH7`B<TqbkNyC`KP_3Mw;D1Ak8-n?)FKRdQpW|_Gnk3527MlcAF<|fQ^>e6o
z6d!7|&nD=vC$NZI_5Tu^++t8<dUiOR&jN!6nB45IfQagiRPYGn6e3kR=hRI}WUuS%
zv~r?WB#l9B4Q_she1I~Z`-#aQFKH~e+~Duv6k~HRBMLhp$CW6nwuC+1fUr>Y=|vzw
z1Q9I-fe?vcx1AJNZgm0}!<m5NlSXxc^D;?G-sDI66TkFogokU>B}H#d-&TI?-^oT*
zRA10W&q#7unMxBUvZJU0H>48~K*CV@D7`H;MzIa8(QDnFN!<(7r69X=cc1~zTKw(l
Pm4SkyKc+`yv*-Q<rDLic

literal 0
HcmV?d00001

diff --git a/includes/content.inc b/includes/content.inc
index a7a2a857..be810d71 100644
--- a/includes/content.inc
+++ b/includes/content.inc
@@ -75,6 +75,9 @@ function ctools_content_defaults($info, &$plugin) {
       if (isset($plugin['required contexts'])) {
         $type['required contexts'] = $plugin['required contexts'];
       }
+      if (isset($plugin['top level'])) {
+        $type['top level'] = $plugin['top level'];
+      }
       $plugin['content types'] = array($plugin['name'] => $type);
     }
     // Otherwise, auto discover the function based upon pattern naming.
@@ -503,7 +506,7 @@ function _ctools_content_create_add_form_info(&$form_info, $info, $plugin, $subt
  * @param $default_types
  *   A default allowed/denied status for content that isn't known about
  */
-function ctools_get_available_content_types($contexts = NULL, $has_content = FALSE, $allowed_types = NULL, $default_types = NULL) {
+function ctools_content_get_available_types($contexts = NULL, $has_content = FALSE, $allowed_types = NULL, $default_types = NULL) {
   $plugins = ctools_get_content_types();
   $available = array();
 
@@ -546,7 +549,7 @@ function ctools_get_available_content_types($contexts = NULL, $has_content = FAL
  * availability.
  *
  */
-function ctools_get_all_content_types() {
+function ctools_content_get_all_types() {
   $plugins = ctools_get_content_types();
   $available = array();
 
diff --git a/js/ajax-responder.js b/js/ajax-responder.js
index 4a09865b..a1db193e 100644
--- a/js/ajax-responder.js
+++ b/js/ajax-responder.js
@@ -29,31 +29,14 @@ Drupal.CTools.AJAX.respond = function(data) {
  * specified by the href of the link.
  */
 Drupal.CTools.AJAX.clickAJAXLink = function() {
-  var url = $(this).attr('href');
-  url.replace('/nojs/', '/ajax/');
-  $.ajax({
-    type: "POST",
-    url: url,
-    data: '',
-    global: true,
-    success: Drupal.CTools.AJAX.respond,
-    error: function() { 
-      alert("An error occurred while attempting to process " + url); 
-    },
-    dataType: 'json'
-  });
-  return false;
-};
+  if ($(this).hasClass('ctools-ajaxing')) {
+    return false;
+  }
 
-/**
- * Generic replacement click handler to open the modal with the destination
- * specified by the href of the link.
- */
-Drupal.CTools.AJAX.clickAJAXButton = function() {
-  // @todo -- if no url we should take the form action and submit the
-  // form.
-  var url = Drupal.CTools.AJAX.findURL(this);
-  if (url) {
+  var url = $(this).attr('href');
+  var object = $(this);
+  $(this).addClass('ctools-ajaxing');
+  try {
     url.replace('/nojs/', '/ajax/');
     $.ajax({
       type: "POST",
@@ -64,25 +47,76 @@ Drupal.CTools.AJAX.clickAJAXButton = function() {
       error: function() { 
         alert("An error occurred while attempting to process " + url); 
       },
-      dataType: 'json'
-    });
-  }
-  else {
-    var form = $(this).parents('form');
-    url = $(form).attr('action');
-    url.replace('/nojs/', '/ajax/');
-    $(form).ajaxSubmit({
-      type: "POST",
-      url: url,
-      data: '',
-      global: true,
-      success: Drupal.CTools.AJAX.respond,
-      error: function() { 
-        alert("An error occurred while attempting to process " + url); 
+      complete: function() {
+        object.removeClass('ctools-ajaxing');
       },
       dataType: 'json'
     });
   }
+  catch (err) {
+    alert("An error occurred while attempting to process " + url); 
+    $(this).removeClass('ctools-ajaxing');
+    return false;
+  }
+
+  return false;
+};
+
+/**
+ * Generic replacement click handler to open the modal with the destination
+ * specified by the href of the link.
+ */
+Drupal.CTools.AJAX.clickAJAXButton = function() {
+  if ($(this).hasClass('ctools-ajaxing')) {
+    return false;
+  }
+
+  var url = Drupal.CTools.AJAX.findURL(this);
+  $(this).addClass('ctools-ajaxing');
+  var object = $(this);
+  try {
+    if (url) {
+      url.replace('/nojs/', '/ajax/');
+      $.ajax({
+        type: "POST",
+        url: url,
+        data: '',
+        global: true,
+        success: Drupal.CTools.AJAX.respond,
+        error: function() { 
+          alert("An error occurred while attempting to process " + url); 
+        },
+        complete: function() {
+          object.removeClass('ctools-ajaxing');
+        },
+        dataType: 'json'
+      });
+    }
+    else {
+      var form = $(this).parents('form');
+      url = $(form).attr('action');
+      url.replace('/nojs/', '/ajax/');
+      $(form).ajaxSubmit({
+        type: "POST",
+        url: url,
+        data: '',
+        global: true,
+        success: Drupal.CTools.AJAX.respond,
+        error: function() { 
+          alert("An error occurred while attempting to process " + url); 
+        },
+        complete: function() {
+          object.removeClass('ctools-ajaxing');
+        },
+        dataType: 'json'
+      });
+    }
+  }
+  catch (err) {
+    alert("An error occurred while attempting to process " + url); 
+    $(this).removeClass('ctools-ajaxing');
+    return false;
+  }
   return false;
 };
 
diff --git a/js/modal.js b/js/modal.js
index 5f7179e1..195156e4 100644
--- a/js/modal.js
+++ b/js/modal.js
@@ -27,7 +27,7 @@ Drupal.CTools.Modal.show = function() {
     });
     $('div.ctools-modal-content .modal-content', context).css({
       'width': ($(window).width() * .8 - 25) + 'px', 
-      'height': ($(window).height() * .8 - 22) + 'px'
+      'height': ($(window).height() * .8 - 35) + 'px'
     });
   }
 
@@ -97,7 +97,12 @@ Drupal.theme.prototype.CToolsModalThrobber = function () {
 Drupal.CTools.Modal.clickAjaxLink = function() {
   // show the empty dialog right away.
   Drupal.CTools.Modal.show();
-  return Drupal.CTools.AJAX.clickAJAXLink.apply(this);
+  Drupal.CTools.AJAX.clickAJAXLink.apply(this);
+  if (!$(this).hasClass('ctools-ajaxing')) {
+    Drupal.CTools.Modal.dismiss();
+  }
+
+  return false;
 };
 
 /**
@@ -105,27 +110,52 @@ Drupal.CTools.Modal.clickAjaxLink = function() {
  * specified by the href of the link.
  */
 Drupal.CTools.Modal.clickAjaxButton = function() {
+  if ($(this).hasClass('ctools-ajaxing')) {
+    return false;
+  }
+
   Drupal.CTools.Modal.show();
-  return Drupal.CTools.AJAX.clickAJAXButton.apply(this);
+  Drupal.CTools.AJAX.clickAJAXButton.apply(this);
+  if (!$(this).hasClass('ctools-ajaxing')) {
+    Drupal.CTools.Modal.dismiss();
+  }
+
+  return false;
 };
 
 /**
  * Submit responder to do an AJAX submit on all modal forms.
  */
 Drupal.CTools.Modal.submitAjaxForm = function() {
+  if ($(this).hasClass('ctools-ajaxing')) {
+    return false;
+  }
+
   url = $(this).attr('action');
-  url.replace('/nojs/', '/ajax/');
-  $(this).ajaxSubmit({
-    type: "POST",
-    url: url,
-    data: '',
-    global: true,
-    success: Drupal.CTools.AJAX.respond,
-    error: function() { 
-      alert("An error occurred while attempting to process " + url); 
-    },
-    dataType: 'json'
-  });
+  $(this).addClass('ctools-ajaxing');
+  var object = $(this);
+  try {
+    url.replace('/nojs/', '/ajax/');
+    $(this).ajaxSubmit({
+      type: "POST",
+      url: url,
+      data: '',
+      global: true,
+      success: Drupal.CTools.AJAX.respond,
+      error: function() { 
+        alert("An error occurred while attempting to process " + url); 
+      },
+      complete: function() {
+        object.removeClass('ctools-ajaxing');
+      },
+      dataType: 'json'
+    });
+  }
+  catch (err) {
+    alert("An error occurred while attempting to process " + url); 
+    $(this).removeClass('ctools-ajaxing');
+    return false;
+  }
   return false;
 }
 
diff --git a/plugins/content_types/block/block.inc b/plugins/content_types/block/block.inc
index be244625..595fe957 100644
--- a/plugins/content_types/block/block.inc
+++ b/plugins/content_types/block/block.inc
@@ -276,17 +276,13 @@ function forum_ctools_block_info($module, $delta, &$info) {
 function profile_ctools_block_info($module, $delta, &$info) {
   // Hide the author information block which isn't as rich as what we can
   // do with context.
-  return NULL;
-  $info['icon'] = 'icon_core_authorinformation.png';
-  $info['category'] = t('Core blocks');
+  $info = NULL;
 }
 
 function book_ctools_block_info($module, $delta, &$info) {
   // Hide the book navigation block which isn't as rich as what we can
   // do with context.
-  return NULL;
-  $info['icon'] = 'icon_core_booknavigation.png';
-  $info['category'] = t('Core blocks');
+  $info = NULL;
 }
 
 function blog_ctools_block_info($module, $delta, &$info) {
diff --git a/plugins/content_types/custom/custom.inc b/plugins/content_types/custom/custom.inc
index 26eb6baf..6fe17eed 100644
--- a/plugins/content_types/custom/custom.inc
+++ b/plugins/content_types/custom/custom.inc
@@ -20,6 +20,9 @@ function ctools_custom_ctools_content_types() {
     'title' => t('New custom content'),
     'icon' => 'icon_block_custom.png',
     'description' => t('Create a completely custom piece of HTML content.'),
+    // Make this a top level category so it appears higher in UIs that support
+    // that.
+    'top level' => TRUE,
     'category' => t('Custom'),
     'defaults' => array('title' => '', 'body' => '', 'format' => FILTER_FORMAT_DEFAULT),
     // render callback is automatically deduced:
-- 
GitLab