57
* Toggle a collapsible's state from open to closed or vice-versa.
59
* @method toggle_collapsible
60
* @param {Node} collapsible the collapsible to toggle.
62
Y.lp.toggle_collapsible = function(collapsible) {
63
// Find the collapse icon and wrapper div for this collapsible.
64
var icon = collapsible.one('.collapseIcon');
66
function get_wrapper_div(node) {
67
var wrapper_div = node.one('.collapseWrapper');
69
// If either the wrapper or the icon is null, raise an error.
70
if (wrapper_div === null) {
71
Y.error("Collapsible has no wrapper div.");
74
Y.error("Collapsible has no icon.");
78
var wrapper_div = get_wrapper_div(collapsible);
80
// Work out the target icon and animation based on the state of
81
// the collapse wrapper. We ignore the current state of the icon
82
// because the collapse wrapper is the canonical guide as to
83
// whether the item is collapsed or expanded. This saves us from
84
// situations where we end up using the wrong icon for a given
89
if (wrapper_div.hasClass('lazr-closed')) {
90
// The wrapper is collapsed; expand it and collapse all its
91
// siblings if it's in an accordion.
93
target_anim = Y.lazr.effects.slide_out(wrapper_div);
94
target_icon = "/@@/treeExpanded";
96
// The wrapper is open; just collapse it.
98
target_anim = Y.lazr.effects.slide_in(wrapper_div);
99
target_icon = "/@@/treeCollapsed";
102
// Run the animation and set the icon src correctly.
104
icon.set('src', target_icon);
106
// Work out if the collapsible is in an accordion and process
107
// the siblings accordingly if the current collapsible is being
109
var parent_node = collapsible.get('parentNode');
110
var in_accordion = parent_node.hasClass('accordion');
111
if (in_accordion && expanding) {
112
var sibling_target_icon = "/@@/treeCollapsed";
113
Y.each(parent_node.all('.collapsible'), function(sibling) {
114
// We only actually collapse the sibling if it's not our
115
// current collapsible.
116
if (sibling != collapsible) {
117
var sibling_wrapper_div = get_wrapper_div(sibling);
118
var sibling_icon = sibling.one('.collapseIcon');
119
var sibling_target_anim = Y.lazr.effects.slide_in(
120
sibling_wrapper_div);
121
sibling_target_anim.run();
122
sibling_icon.set('src', sibling_target_icon);
129
57
* Activate all collapsible sections of a page.
131
59
* @method activate_collapsibles
133
61
Y.lp.activate_collapsibles = function() {
134
// Grab the collapsibles.
135
Y.all('.collapsible').each(function(collapsible) {
137
// Try to grab the legend in the usual way.
138
var legend = collapsible.one('legend');
139
if (legend === null) {
140
// If it's null, this might be a collapsible div, not
141
// fieldset, so try to grab the div's "legend".
142
legend = collapsible.one('.config-options');
144
if (legend === null ||
145
legend.one('.collapseIcon') !== null) {
146
// If there's no legend there's not much we can do,
147
// so just exit this iteration. If there's a
148
// collapseIcon in there we consider the collapsible
149
// to already have been set up and therefore ignore
150
// it this time around.
154
var icon = Y.Node.create(
155
'<img src="/@@/treeExpanded" class="collapseIcon" />');
157
// We use javascript:void(0) here (though it will cause
158
// lint to complain) because it prevents clicking on the
159
// anchor from altering the page URL, which can subtly
161
var anchor = Y.Node.create(
162
'<a href="javascript:void(0);"></a>');
163
anchor.appendChild(icon);
165
// Move the contents of the legend into the span. We use
166
// the verbose version of <span /> to avoid silly
167
// breakages in Firefox.
168
var span = Y.Node.create('<span></span>');
169
var legend_children = legend.get('children');
172
if (Y.Lang.isValue(legend_children)) {
173
// XXX 2009-07-06 gmb Account for oddness from
174
// Node.get('children'); (see YUI ticket 2528028 for
176
len = legend_children.size ?
177
legend_children.size() : legend_children.length;
183
// If the legend has child elements, move them
184
// across one by one.
185
Y.each(legend_children, function(child_node) {
186
if (child_node.get('tagName') == 'A') {
187
// If this child is an anchor, add only its
188
// contents to the span.
189
new_node = Y.Node.create(
190
child_node.get('innerHTML'));
191
span.appendChild(new_node);
192
legend.removeChild(child_node);
194
// Otherwise, add the node to the span as it
196
span.appendChild(child_node);
200
// Otherwise just move the innerHTML across as a
201
// block. Once the span is appended to the anchor,
202
// this will essentially turn the contents of the
203
// legend into a link.
204
span.set('innerHTML', legend.get('innerHTML'));
205
legend.set('innerHTML', '');
208
// Replace the contents of the legend with the anchor.
209
anchor.appendChild(span);
210
legend.appendChild(anchor);
212
// Put a wrapper around the fieldset contents for ease
214
var wrapper_div = Y.Node.create(
215
'<div class="collapseWrapper" />');
217
// Loop over the children of the collapsible and move them
218
// into the wrapper div. We remove the legend from the
219
// collapsible at this point to make sure it gets left
220
// outside the wrapper div; we'll add it again later.
221
collapsible.removeChild(legend);
223
// "Why do this as a while?" I hear you cry. Well, it's
224
// because using Y.each() leads to interesting results
225
// in FF3.5, Opera and Chrome, since by doing
226
// appendChild() with each child node (and thus removing
227
// them from the collapsible) means you're altering the
228
// collection as you're looping over it, which is a Bad
229
// Thing. This isn't as pretty but it actually works.
230
var first_child = collapsible.one(':first-child');
231
while (Y.Lang.isValue(first_child)) {
232
wrapper_div.appendChild(first_child);
233
first_child = collapsible.one(':first-child');
236
// Put the legend and the new wrapper div into the
237
// collapsible in the right order.
238
collapsible.appendChild(legend);
239
collapsible.appendChild(wrapper_div);
241
// If the collapsible is to be collapsed on pageload, do
243
if (collapsible.hasClass('collapsed')) {
244
// Strip out the 'collapsed' class as it's no longer
246
collapsible.removeClass('collapsed');
248
// We use the slide_in effect to hide the
249
// collapsible because it sets up all the properties
250
// and classes for the element properly and saves us
251
// from embarrasment later on.
252
var slide_in = Y.lazr.effects.slide_in(wrapper_div);
255
icon.set('src', '/@@/treeCollapsed');
258
// Finally, add toggle_collapsible() as an onclick
259
// handler to the anchor.
260
anchor.on('click', function(e) {
261
Y.lp.toggle_collapsible(collapsible);
62
// CSS selector 'legend + *' gets the next sibling element.
63
Y.lp.app.widgets.expander.createByCSS(
64
'.collapsible', 'legend', 'legend + *', true);
265
67
Y.lp.get_url_path = function(url) {
266
68
return Y.Node.create('<a>junk</a>').set('href', url).get('pathname');
268
}, "0.1", {"requires":["cookie", "lazr.effects"]});
70
}, "0.1", {"requires":["cookie", "lazr.effects", "lp.app.widgets.expander"]});
271
73
// Lint-safe scripting URL.