danielebarchiesi@0: /** danielebarchiesi@0: * @file danielebarchiesi@0: * Javascript required for a simple collapsible div. danielebarchiesi@0: * danielebarchiesi@0: * Creating a collapsible div with this doesn't take too much. There are danielebarchiesi@0: * three classes necessary: danielebarchiesi@0: * danielebarchiesi@0: * - ctools-collapsible-container: This is the overall container that will be danielebarchiesi@0: * collapsible. This must be a div. danielebarchiesi@0: * - ctools-collapsible-handle: This is the title area, and is what will be danielebarchiesi@0: * visible when it is collapsed. This can be any block element, such as div danielebarchiesi@0: * or h2. danielebarchiesi@0: * - ctools-collapsible-content: This is the ocntent area and will only be danielebarchiesi@0: * visible when expanded. This must be a div. danielebarchiesi@0: * danielebarchiesi@0: * Adding 'ctools-collapsible-remember' to the container class will cause the danielebarchiesi@0: * state of the container to be stored in a cookie, and remembered from page danielebarchiesi@0: * load to page load. This will only work if the container has a unique ID, so danielebarchiesi@0: * very carefully add IDs to your containers. danielebarchiesi@0: * danielebarchiesi@0: * If the class 'ctools-no-container' is placed on the container, the container danielebarchiesi@0: * will be the handle. The content will be found by appending '-content' to the danielebarchiesi@0: * id of the handle. The ctools-collapsible-handle and danielebarchiesi@0: * ctools-collapsible-content classes will not be required in that case, and no danielebarchiesi@0: * restrictions on what of data the container is are placed. Like danielebarchiesi@0: * ctools-collapsible-remember this requires an id to eist. danielebarchiesi@0: * danielebarchiesi@0: * The content will be 'open' unless the container class has 'ctools-collapsed' danielebarchiesi@0: * as a class, which will cause the container to draw collapsed. danielebarchiesi@0: */ danielebarchiesi@0: danielebarchiesi@0: (function ($) { danielebarchiesi@0: // All CTools tools begin with this if they need to use the CTools namespace. danielebarchiesi@0: if (!Drupal.CTools) { danielebarchiesi@0: Drupal.CTools = {}; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Object to store state. danielebarchiesi@0: * danielebarchiesi@0: * This object will remember the state of collapsible containers. The first danielebarchiesi@0: * time a state is requested, it will check the cookie and set up the variable. danielebarchiesi@0: * If a state has been changed, when the window is unloaded the state will be danielebarchiesi@0: * saved. danielebarchiesi@0: */ danielebarchiesi@0: Drupal.CTools.Collapsible = { danielebarchiesi@0: state: {}, danielebarchiesi@0: stateLoaded: false, danielebarchiesi@0: stateChanged: false, danielebarchiesi@0: cookieString: 'ctools-collapsible-state=', danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Get the current collapsed state of a container. danielebarchiesi@0: * danielebarchiesi@0: * If set to 1, the container is open. If set to -1, the container is danielebarchiesi@0: * collapsed. If unset the state is unknown, and the default state should danielebarchiesi@0: * be used. danielebarchiesi@0: */ danielebarchiesi@0: getState: function (id) { danielebarchiesi@0: if (!this.stateLoaded) { danielebarchiesi@0: this.loadCookie(); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: return this.state[id]; danielebarchiesi@0: }, danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Set the collapsed state of a container for subsequent page loads. danielebarchiesi@0: * danielebarchiesi@0: * Set the state to 1 for open, -1 for collapsed. danielebarchiesi@0: */ danielebarchiesi@0: setState: function (id, state) { danielebarchiesi@0: if (!this.stateLoaded) { danielebarchiesi@0: this.loadCookie(); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: this.state[id] = state; danielebarchiesi@0: danielebarchiesi@0: if (!this.stateChanged) { danielebarchiesi@0: this.stateChanged = true; danielebarchiesi@0: $(window).unload(this.unload); danielebarchiesi@0: } danielebarchiesi@0: }, danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Check the cookie and load the state variable. danielebarchiesi@0: */ danielebarchiesi@0: loadCookie: function () { danielebarchiesi@0: // If there is a previous instance of this cookie danielebarchiesi@0: if (document.cookie.length > 0) { danielebarchiesi@0: // Get the number of characters that have the list of values danielebarchiesi@0: // from our string index. danielebarchiesi@0: offset = document.cookie.indexOf(this.cookieString); danielebarchiesi@0: danielebarchiesi@0: // If its positive, there is a list! danielebarchiesi@0: if (offset != -1) { danielebarchiesi@0: offset += this.cookieString.length; danielebarchiesi@0: var end = document.cookie.indexOf(';', offset); danielebarchiesi@0: if (end == -1) { danielebarchiesi@0: end = document.cookie.length; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // Get a list of all values that are saved on our string danielebarchiesi@0: var cookie = unescape(document.cookie.substring(offset, end)); danielebarchiesi@0: danielebarchiesi@0: if (cookie != '') { danielebarchiesi@0: var cookieList = cookie.split(','); danielebarchiesi@0: for (var i = 0; i < cookieList.length; i++) { danielebarchiesi@0: var info = cookieList[i].split(':'); danielebarchiesi@0: this.state[info[0]] = info[1]; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: this.stateLoaded = true; danielebarchiesi@0: }, danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Turn the state variable into a string and store it in the cookie. danielebarchiesi@0: */ danielebarchiesi@0: storeCookie: function () { danielebarchiesi@0: var cookie = ''; danielebarchiesi@0: danielebarchiesi@0: // Get a list of IDs, saparated by comma danielebarchiesi@0: for (i in this.state) { danielebarchiesi@0: if (cookie != '') { danielebarchiesi@0: cookie += ','; danielebarchiesi@0: } danielebarchiesi@0: cookie += i + ':' + this.state[i]; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // Save this values on the cookie danielebarchiesi@0: document.cookie = this.cookieString + escape(cookie) + ';path=/'; danielebarchiesi@0: }, danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Respond to the unload event by storing the current state. danielebarchiesi@0: */ danielebarchiesi@0: unload: function() { danielebarchiesi@0: Drupal.CTools.Collapsible.storeCookie(); danielebarchiesi@0: } danielebarchiesi@0: }; danielebarchiesi@0: danielebarchiesi@0: // Set up an array for callbacks. danielebarchiesi@0: Drupal.CTools.CollapsibleCallbacks = []; danielebarchiesi@0: Drupal.CTools.CollapsibleCallbacksAfterToggle = []; danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Bind collapsible behavior to a given container. danielebarchiesi@0: */ danielebarchiesi@0: Drupal.CTools.bindCollapsible = function () { danielebarchiesi@0: var $container = $(this); danielebarchiesi@0: danielebarchiesi@0: // Allow the specification of the 'no container' class, which means the danielebarchiesi@0: // handle and the container can be completely independent. danielebarchiesi@0: if ($container.hasClass('ctools-no-container') && $container.attr('id')) { danielebarchiesi@0: // In this case, the container *is* the handle and the content is found danielebarchiesi@0: // by adding '-content' to the id. Obviously, an id is required. danielebarchiesi@0: var handle = $container; danielebarchiesi@0: var content = $('#' + $container.attr('id') + '-content'); danielebarchiesi@0: } danielebarchiesi@0: else { danielebarchiesi@0: var handle = $container.children('.ctools-collapsible-handle'); danielebarchiesi@0: var content = $container.children('div.ctools-collapsible-content'); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: if (content.length) { danielebarchiesi@0: // Create the toggle item and place it in front of the toggle. danielebarchiesi@0: var toggle = $(''); danielebarchiesi@0: handle.before(toggle); danielebarchiesi@0: danielebarchiesi@0: // If the remember class is set, check to see if we have a remembered danielebarchiesi@0: // state stored. danielebarchiesi@0: if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) { danielebarchiesi@0: var state = Drupal.CTools.Collapsible.getState($container.attr('id')); danielebarchiesi@0: if (state == 1) { danielebarchiesi@0: $container.removeClass('ctools-collapsed'); danielebarchiesi@0: } danielebarchiesi@0: else if (state == -1) { danielebarchiesi@0: $container.addClass('ctools-collapsed'); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // If we should start collapsed, do so: danielebarchiesi@0: if ($container.hasClass('ctools-collapsed')) { danielebarchiesi@0: toggle.toggleClass('ctools-toggle-collapsed'); danielebarchiesi@0: content.hide(); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: var afterToggle = function () { danielebarchiesi@0: if (Drupal.CTools.CollapsibleCallbacksAfterToggle) { danielebarchiesi@0: for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) { danielebarchiesi@0: Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: var clickMe = function () { danielebarchiesi@0: if (Drupal.CTools.CollapsibleCallbacks) { danielebarchiesi@0: for (i in Drupal.CTools.CollapsibleCallbacks) { danielebarchiesi@0: Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // If the container is a table element slideToggle does not do what danielebarchiesi@0: // we want, so use toggle() instead. danielebarchiesi@0: if ($container.is('table')) { danielebarchiesi@0: content.toggle(0, afterToggle); danielebarchiesi@0: } danielebarchiesi@0: else { danielebarchiesi@0: content.slideToggle(100, afterToggle); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: toggle.toggleClass('ctools-toggle-collapsed'); danielebarchiesi@0: danielebarchiesi@0: // If we're supposed to remember the state of this class, do so. danielebarchiesi@0: if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) { danielebarchiesi@0: var state = toggle.hasClass('ctools-toggle-collapsed') ? -1 : 1; danielebarchiesi@0: Drupal.CTools.Collapsible.setState($container.attr('id'), state); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: return false; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // Let both the toggle and the handle be clickable. danielebarchiesi@0: toggle.click(clickMe); danielebarchiesi@0: handle.click(clickMe); danielebarchiesi@0: } danielebarchiesi@0: }; danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Support Drupal's 'behaviors' system for binding. danielebarchiesi@0: */ danielebarchiesi@0: Drupal.behaviors.CToolsCollapsible = { danielebarchiesi@0: attach: function(context) { danielebarchiesi@0: $('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: })(jQuery);