collapsible-div.js
7.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/**
* @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);