comparison sites/all/modules/ctools/js/collapsible-div.js @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ff03f76ab3fe
1 /**
2 * @file
3 * Javascript required for a simple collapsible div.
4 *
5 * Creating a collapsible div with this doesn't take too much. There are
6 * three classes necessary:
7 *
8 * - ctools-collapsible-container: This is the overall container that will be
9 * collapsible. This must be a div.
10 * - ctools-collapsible-handle: This is the title area, and is what will be
11 * visible when it is collapsed. This can be any block element, such as div
12 * or h2.
13 * - ctools-collapsible-content: This is the ocntent area and will only be
14 * visible when expanded. This must be a div.
15 *
16 * Adding 'ctools-collapsible-remember' to the container class will cause the
17 * state of the container to be stored in a cookie, and remembered from page
18 * load to page load. This will only work if the container has a unique ID, so
19 * very carefully add IDs to your containers.
20 *
21 * If the class 'ctools-no-container' is placed on the container, the container
22 * will be the handle. The content will be found by appending '-content' to the
23 * id of the handle. The ctools-collapsible-handle and
24 * ctools-collapsible-content classes will not be required in that case, and no
25 * restrictions on what of data the container is are placed. Like
26 * ctools-collapsible-remember this requires an id to eist.
27 *
28 * The content will be 'open' unless the container class has 'ctools-collapsed'
29 * as a class, which will cause the container to draw collapsed.
30 */
31
32 (function ($) {
33 // All CTools tools begin with this if they need to use the CTools namespace.
34 if (!Drupal.CTools) {
35 Drupal.CTools = {};
36 }
37
38 /**
39 * Object to store state.
40 *
41 * This object will remember the state of collapsible containers. The first
42 * time a state is requested, it will check the cookie and set up the variable.
43 * If a state has been changed, when the window is unloaded the state will be
44 * saved.
45 */
46 Drupal.CTools.Collapsible = {
47 state: {},
48 stateLoaded: false,
49 stateChanged: false,
50 cookieString: 'ctools-collapsible-state=',
51
52 /**
53 * Get the current collapsed state of a container.
54 *
55 * If set to 1, the container is open. If set to -1, the container is
56 * collapsed. If unset the state is unknown, and the default state should
57 * be used.
58 */
59 getState: function (id) {
60 if (!this.stateLoaded) {
61 this.loadCookie();
62 }
63
64 return this.state[id];
65 },
66
67 /**
68 * Set the collapsed state of a container for subsequent page loads.
69 *
70 * Set the state to 1 for open, -1 for collapsed.
71 */
72 setState: function (id, state) {
73 if (!this.stateLoaded) {
74 this.loadCookie();
75 }
76
77 this.state[id] = state;
78
79 if (!this.stateChanged) {
80 this.stateChanged = true;
81 $(window).unload(this.unload);
82 }
83 },
84
85 /**
86 * Check the cookie and load the state variable.
87 */
88 loadCookie: function () {
89 // If there is a previous instance of this cookie
90 if (document.cookie.length > 0) {
91 // Get the number of characters that have the list of values
92 // from our string index.
93 offset = document.cookie.indexOf(this.cookieString);
94
95 // If its positive, there is a list!
96 if (offset != -1) {
97 offset += this.cookieString.length;
98 var end = document.cookie.indexOf(';', offset);
99 if (end == -1) {
100 end = document.cookie.length;
101 }
102
103 // Get a list of all values that are saved on our string
104 var cookie = unescape(document.cookie.substring(offset, end));
105
106 if (cookie != '') {
107 var cookieList = cookie.split(',');
108 for (var i = 0; i < cookieList.length; i++) {
109 var info = cookieList[i].split(':');
110 this.state[info[0]] = info[1];
111 }
112 }
113 }
114 }
115
116 this.stateLoaded = true;
117 },
118
119 /**
120 * Turn the state variable into a string and store it in the cookie.
121 */
122 storeCookie: function () {
123 var cookie = '';
124
125 // Get a list of IDs, saparated by comma
126 for (i in this.state) {
127 if (cookie != '') {
128 cookie += ',';
129 }
130 cookie += i + ':' + this.state[i];
131 }
132
133 // Save this values on the cookie
134 document.cookie = this.cookieString + escape(cookie) + ';path=/';
135 },
136
137 /**
138 * Respond to the unload event by storing the current state.
139 */
140 unload: function() {
141 Drupal.CTools.Collapsible.storeCookie();
142 }
143 };
144
145 // Set up an array for callbacks.
146 Drupal.CTools.CollapsibleCallbacks = [];
147 Drupal.CTools.CollapsibleCallbacksAfterToggle = [];
148
149 /**
150 * Bind collapsible behavior to a given container.
151 */
152 Drupal.CTools.bindCollapsible = function () {
153 var $container = $(this);
154
155 // Allow the specification of the 'no container' class, which means the
156 // handle and the container can be completely independent.
157 if ($container.hasClass('ctools-no-container') && $container.attr('id')) {
158 // In this case, the container *is* the handle and the content is found
159 // by adding '-content' to the id. Obviously, an id is required.
160 var handle = $container;
161 var content = $('#' + $container.attr('id') + '-content');
162 }
163 else {
164 var handle = $container.children('.ctools-collapsible-handle');
165 var content = $container.children('div.ctools-collapsible-content');
166 }
167
168 if (content.length) {
169 // Create the toggle item and place it in front of the toggle.
170 var toggle = $('<span class="ctools-toggle"></span>');
171 handle.before(toggle);
172
173 // If the remember class is set, check to see if we have a remembered
174 // state stored.
175 if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
176 var state = Drupal.CTools.Collapsible.getState($container.attr('id'));
177 if (state == 1) {
178 $container.removeClass('ctools-collapsed');
179 }
180 else if (state == -1) {
181 $container.addClass('ctools-collapsed');
182 }
183 }
184
185 // If we should start collapsed, do so:
186 if ($container.hasClass('ctools-collapsed')) {
187 toggle.toggleClass('ctools-toggle-collapsed');
188 content.hide();
189 }
190
191 var afterToggle = function () {
192 if (Drupal.CTools.CollapsibleCallbacksAfterToggle) {
193 for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
194 Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle);
195 }
196 }
197 }
198
199 var clickMe = function () {
200 if (Drupal.CTools.CollapsibleCallbacks) {
201 for (i in Drupal.CTools.CollapsibleCallbacks) {
202 Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle);
203 }
204 }
205
206 // If the container is a table element slideToggle does not do what
207 // we want, so use toggle() instead.
208 if ($container.is('table')) {
209 content.toggle(0, afterToggle);
210 }
211 else {
212 content.slideToggle(100, afterToggle);
213 }
214
215 toggle.toggleClass('ctools-toggle-collapsed');
216
217 // If we're supposed to remember the state of this class, do so.
218 if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
219 var state = toggle.hasClass('ctools-toggle-collapsed') ? -1 : 1;
220 Drupal.CTools.Collapsible.setState($container.attr('id'), state);
221 }
222
223 return false;
224 }
225
226 // Let both the toggle and the handle be clickable.
227 toggle.click(clickMe);
228 handle.click(clickMe);
229 }
230 };
231
232 /**
233 * Support Drupal's 'behaviors' system for binding.
234 */
235 Drupal.behaviors.CToolsCollapsible = {
236 attach: function(context) {
237 $('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible);
238 }
239 }
240 })(jQuery);