242 lines
7.8 KiB
JavaScript
242 lines
7.8 KiB
JavaScript
/**
|
|
* @file
|
|
* Javascript required for a simple collapsible div.
|
|
*
|
|
* 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
|
|
* 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.
|
|
*
|
|
* If the class 'ctools-no-container' is placed on the container, the container
|
|
* will be the handle. The content will be found by appending '-content' to the
|
|
* id of the handle. The ctools-collapsible-handle and
|
|
* ctools-collapsible-content classes will not be required in that case, and no
|
|
* restrictions on what of data the container is are placed. Like
|
|
* ctools-collapsible-remember this requires an id to eist.
|
|
*
|
|
* The content will be 'open' unless the container class has 'ctools-collapsed'
|
|
* as a class, which will cause the container to draw collapsed.
|
|
*/
|
|
|
|
(function ($) {
|
|
// All CTools tools begin with this if they need to use the CTools namespace.
|
|
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 = [];
|
|
Drupal.CTools.CollapsibleCallbacksAfterToggle = [];
|
|
|
|
/**
|
|
* Bind collapsible behavior to a given container.
|
|
*/
|
|
Drupal.CTools.bindCollapsible = function () {
|
|
var $container = $(this);
|
|
|
|
// Allow the specification of the 'no container' class, which means the
|
|
// handle and the container can be completely independent.
|
|
if ($container.hasClass('ctools-no-container') && $container.attr('id')) {
|
|
// In this case, the container *is* the handle and the content is found
|
|
// by adding '-content' to the id. Obviously, an id is required.
|
|
var handle = $container;
|
|
var content = $('#' + $container.attr('id') + '-content');
|
|
}
|
|
else {
|
|
var handle = $container.children('.ctools-collapsible-handle');
|
|
var content = $container.children('div.ctools-collapsible-content');
|
|
}
|
|
|
|
if (content.length) {
|
|
// Create the toggle item and place it in front of the toggle.
|
|
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 () {
|
|
if (Drupal.CTools.CollapsibleCallbacksAfterToggle) {
|
|
for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
|
|
Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle);
|
|
}
|
|
}
|
|
}
|
|
|
|
var clickMe = function () {
|
|
if (Drupal.CTools.CollapsibleCallbacks) {
|
|
for (i in Drupal.CTools.CollapsibleCallbacks) {
|
|
Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle);
|
|
}
|
|
}
|
|
|
|
// If the container is a table element slideToggle does not do what
|
|
// we want, so use toggle() instead.
|
|
if ($container.is('table')) {
|
|
content.toggle(0, afterToggle);
|
|
}
|
|
else {
|
|
content.slideToggle(100, afterToggle);
|
|
}
|
|
|
|
$container.toggleClass('ctools-collapsed');
|
|
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);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Let both the toggle and the handle be clickable.
|
|
toggle.click(clickMe);
|
|
handle.click(clickMe);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Support Drupal's 'behaviors' system for binding.
|
|
*/
|
|
Drupal.behaviors.CToolsCollapsible = {
|
|
attach: function(context) {
|
|
$('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible);
|
|
}
|
|
}
|
|
})(jQuery);
|