? 2009-09-02-string-context-html_safe.patch
? 558918-collapsible-remember.patch
? TODO.txt
? ctools-wizard-default_1.patch
? ctools-wizard-default_2.patch
? ctools.ajax-redirect_0.patch
? ctools.ajax-responder.js__0.patch
? ctools.info_file.patch
? ctools.info_file_0.patch
? ctools_user_profile_content_type-569508-1.patch
? ctools_wizard.html_back.patch
? ctools_wizard.inc_cancelpath.patch
? custom_with_php_filter-525538-5.patch
? views_optional_contexts.patch
Index: includes/collapsible.theme.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ctools/includes/collapsible.theme.inc,v
retrieving revision 1.4
diff -u -p -r1.4 collapsible.theme.inc
--- includes/collapsible.theme.inc	29 Jan 2009 22:12:05 -0000	1.4
+++ includes/collapsible.theme.inc	9 Sep 2009 21:28:06 -0000
@@ -18,13 +18,15 @@ function ctools_collapsible_theme(&$item
     'arguments' => array('handle' => NULL, 'content' => NULL, 'collapsed' => FALSE),
     'file' => 'includes/collapsible.theme.inc',
   );
+  $items['ctools_collapsible_remembered'] = array(
+    'arguments' => array('id' => NULL, 'handle' => NULL, 'content' => NULL, 'collapsed' => FALSE),
+    'file' => 'includes/collapsible.theme.inc',
+  );
 }
 
 /**
  * Render a collapsible div.
  *
- * @todo Should this be a tpl.php with preprocess?
- *
  * @param $handle
  *   Text to put in the handle/title area of the div.
  * @param $content
@@ -46,3 +48,29 @@ function theme_ctools_collapsible($handl
   return $output;
 }
 
+/**
+ * Render a collapsible div whose state will be remembered.
+ *
+ * @param $id
+ *   The CSS id of the container. This is required.
+ * @param $handle
+ *   Text to put in the handle/title area of the div.
+ * @param $content
+ *   Text to put in the content area of the div, this is what will get
+ *   collapsed
+ * @param $collapsed = FALSE
+ *   If true, this div will start out collapsed.
+ */
+function theme_ctools_collapsible_remembered($id, $handle, $content, $collapsed = FALSE) {
+  ctools_add_js('collapsible-div');
+  ctools_add_css('collapsible-div');
+
+  $class = $collapsed ? ' ctools-collapsed' : '';
+  $output = '<div id="' . $id . '" class="ctools-collapsible-remember ctools-collapsible-container' . $class . '">';
+  $output .= '<div class="ctools-collapsible-handle">' . $handle . '</div>';
+  $output .= '<div class="ctools-collapsible-content">' . $content . '</div>';
+  $output .= '</div>';
+
+  return $output;
+}
+
Index: js/collapsible-div.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ctools/js/collapsible-div.js,v
retrieving revision 1.3
diff -u -p -r1.3 collapsible-div.js
--- js/collapsible-div.js	19 Dec 2008 17:35:58 -0000	1.3
+++ js/collapsible-div.js	9 Sep 2009 21:28:06 -0000
@@ -3,17 +3,22 @@
  * @file
  * Javascript required for a simple collapsible div.
  *
- * Creating a collapsible div with this doesn't take too much. There are 
+ * Creating a collapsible div with this doesn't take too much. There are
  * three classes necessary:
  *
  * - ctools-collapsible-container: This is the overall container that will be
  *   collapsible. This must be a div.
  * - ctools-collapsible-handle: This is the title area, and is what will be
- *   visible when it is collapsed. This can be any block element, such as div 
+ *   visible when it is collapsed. This can be any block element, such as div
  *   or h2.
  * - ctools-collapsible-content: This is the ocntent area and will only be
  *   visible when expanded. This must be a div.
  *
+ * Adding 'ctools-collapsible-remember' to the container class will cause the
+ * state of the container to be stored in a cookie, and remembered from page
+ * load to page load. This will only work if the container has a unique ID, so
+ * very carefully add IDs to your containers.
+ *
  * The div will be 'open' unless the container class has 'ctools-collapsed' as
  * a class, which will cause the container to draw collapsed.
  */
@@ -23,6 +28,112 @@ if (!Drupal.CTools) {
   Drupal.CTools = {};
 }
 
+/**
+ * Object to store state.
+ *
+ * This object will remember the state of collapsible containers. The first
+ * time a state is requested, it will check the cookie and set up the variable.
+ * If a state has been changed, when the window is unloaded the state will be
+ * saved.
+ */
+Drupal.CTools.Collapsible = {
+  state: {},
+  stateLoaded: false,
+  stateChanged: false,
+  cookieString: 'ctools-collapsible-state=',
+
+  /**
+   * Get the current collapsed state of a container.
+   *
+   * If set to 1, the container is open. If set to -1, the container is
+   * collapsed. If unset the state is unknown, and the default state should
+   * be used.
+   */
+  getState: function (id) {
+    if (!this.stateLoaded) {
+      this.loadCookie();
+    }
+
+    return this.state[id];
+  },
+
+  /**
+   * Set the collapsed state of a container for subsequent page loads.
+   *
+   * Set the state to 1 for open, -1 for collapsed.
+   */
+  setState: function (id, state) {
+    if (!this.stateLoaded) {
+      this.loadCookie();
+    }
+
+    this.state[id] = state;
+
+    if (!this.stateChanged) {
+      this.stateChanged = true;
+      $(window).unload(this.unload);
+    }
+  },
+
+  /**
+   * Check the cookie and load the state variable.
+   */
+  loadCookie: function () {
+    // If there is a previous instance of this cookie
+    if (document.cookie.length > 0) {
+      // Get the number of characters that have the list of values
+      // from our string index.
+      offset = document.cookie.indexOf(this.cookieString);
+
+      // If its positive, there is a list!
+      if (offset != -1) {
+        offset += this.cookieString.length;
+        var end = document.cookie.indexOf(';', offset);
+        if (end == -1) {
+          end = document.cookie.length;
+        }
+
+        // Get a list of all values that are saved on our string
+        var cookie = unescape(document.cookie.substring(offset, end));
+
+        if (cookie != '') {
+          var cookieList = cookie.split(',');
+          for (var i = 0; i < cookieList.length; i++) {
+            var info = cookieList[i].split(':');
+            this.state[info[0]] = info[1];
+          }
+        }
+      }
+    }
+
+    this.stateLoaded = true;
+  },
+
+  /**
+   * Turn the state variable into a string and store it in the cookie.
+   */
+  storeCookie: function () {
+    var cookie = '';
+
+    // Get a list of IDs, saparated by comma
+    for (i in this.state) {
+      if (cookie != '') {
+        cookie += ',';
+      }
+      cookie += i + ':' + this.state[i];
+    }
+
+    // Save this values on the cookie
+    document.cookie = this.cookieString + escape(cookie) + ';path=/';
+  },
+
+  /**
+   * Respond to the unload event by storing the current state.
+   */
+  unload: function() {
+    Drupal.CTools.Collapsible.storeCookie();
+  }
+};
 
 // Set up an array for callbacks.
 Drupal.CTools.CollapsibleCallbacks = [];
@@ -31,7 +142,7 @@ Drupal.CTools.CollapsibleCallbacksAfterT
 /**
  * Bind collapsible behavior to a given container.
  */
-Drupal.CTools.bindCollapsible = function() {
+Drupal.CTools.bindCollapsible = function () {
   var $container = $(this);
 
   var handle = $container.children('.ctools-collapsible-handle');
@@ -41,21 +152,33 @@ Drupal.CTools.bindCollapsible = function
     var toggle = $('<span class="ctools-toggle"></span>');
     handle.before(toggle);
 
+    // If the remember class is set, check to see if we have a remembered
+    // state stored.
+    if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
+      var state = Drupal.CTools.Collapsible.getState($container.attr('id'));
+      if (state == 1) {
+        $container.removeClass('ctools-collapsed');
+      }
+      else if (state == -1) {
+        $container.addClass('ctools-collapsed');
+      }
+    }
+
     // If we should start collapsed, do so:
     if ($container.hasClass('ctools-collapsed')) {
       toggle.toggleClass('ctools-toggle-collapsed');
       content.hide();
     }
 
-    var afterToggle = function() {
+    var afterToggle = function () {
       if (Drupal.CTools.CollapsibleCallbacksAfterToggle) {
         for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
           Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle);
         }
       }
     }
-    
-    var clickMe = function() {
+
+    var clickMe = function () {
       if (Drupal.CTools.CollapsibleCallbacks) {
         for (i in Drupal.CTools.CollapsibleCallbacks) {
           Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle);
@@ -63,6 +186,12 @@ Drupal.CTools.bindCollapsible = function
       }
       content.slideToggle(100, afterToggle);
       toggle.toggleClass('ctools-toggle-collapsed');
+
+      // If we're supposed to remember the state of this class, do so.
+      if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
+        var state = toggle.hasClass('ctools-toggle-collapsed') ? -1 : 1;
+        Drupal.CTools.Collapsible.setState($container.attr('id'), state);
+      }
     }
 
     // Let both the toggle and the handle be clickable.
