~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/app/javascript/lp.js

  • Committer: Colin Watson
  • Date: 2011-08-19 00:25:11 UTC
  • mfrom: (7675.1045.728 db-devel)
  • mto: This revision was merged to the branch mainline in revision 13909.
  • Revision ID: cjwatson@canonical.com-20110819002511-0x8hrqs1ckiqk53g
merge db-devel

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    };
55
55
 
56
56
    /**
57
 
     * Toggle a collapsible's state from open to closed or vice-versa.
58
 
     *
59
 
     * @method toggle_collapsible
60
 
     * @param {Node} collapsible the collapsible to toggle.
61
 
     */
62
 
    Y.lp.toggle_collapsible = function(collapsible) {
63
 
        // Find the collapse icon and wrapper div for this collapsible.
64
 
        var icon = collapsible.one('.collapseIcon');
65
 
 
66
 
        function get_wrapper_div(node) {
67
 
            var wrapper_div = node.one('.collapseWrapper');
68
 
 
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.");
72
 
            }
73
 
            if (icon === null) {
74
 
                Y.error("Collapsible has no icon.");
75
 
            }
76
 
            return wrapper_div;
77
 
        }
78
 
        var wrapper_div = get_wrapper_div(collapsible);
79
 
 
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
85
 
        // state.
86
 
        var target_icon;
87
 
        var target_anim;
88
 
        var expanding;
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.
92
 
            expanding = true;
93
 
            target_anim = Y.lazr.effects.slide_out(wrapper_div);
94
 
            target_icon = "/@@/treeExpanded";
95
 
        } else {
96
 
            // The wrapper is open; just collapse it.
97
 
            expanding = false;
98
 
            target_anim = Y.lazr.effects.slide_in(wrapper_div);
99
 
            target_icon = "/@@/treeCollapsed";
100
 
        }
101
 
 
102
 
        // Run the animation and set the icon src correctly.
103
 
        target_anim.run();
104
 
        icon.set('src', target_icon);
105
 
 
106
 
        // Work out if the collapsible is in an accordion and process
107
 
        // the siblings accordingly if the current collapsible is being
108
 
        // expanded.
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);
123
 
                }
124
 
            });
125
 
        }
126
 
    };
127
 
 
128
 
    /**
129
57
     * Activate all collapsible sections of a page.
130
58
     *
131
59
     * @method activate_collapsibles
132
60
     */
133
61
    Y.lp.activate_collapsibles = function() {
134
 
        // Grab the collapsibles.
135
 
        Y.all('.collapsible').each(function(collapsible) {
136
 
 
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');
143
 
            }
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.
151
 
                return;
152
 
            }
153
 
 
154
 
            var icon = Y.Node.create(
155
 
                '<img src="/@@/treeExpanded" class="collapseIcon" />');
156
 
 
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
160
 
            // break things.
161
 
            var anchor = Y.Node.create(
162
 
                '<a href="javascript:void(0);"></a>');
163
 
            anchor.appendChild(icon);
164
 
 
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');
170
 
            var len;
171
 
 
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
175
 
                // details).
176
 
                len = legend_children.size ?
177
 
                    legend_children.size() : legend_children.length;
178
 
            } else {
179
 
                len = 0;
180
 
            }
181
 
 
182
 
            if (len > 0) {
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);
193
 
                    } else {
194
 
                        // Otherwise, add the node to the span as it
195
 
                        // is.
196
 
                        span.appendChild(child_node);
197
 
                    }
198
 
                });
199
 
            } else {
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', '');
206
 
            }
207
 
 
208
 
            // Replace the contents of the legend with the anchor.
209
 
            anchor.appendChild(span);
210
 
            legend.appendChild(anchor);
211
 
 
212
 
            // Put a wrapper around the fieldset contents for ease
213
 
            // of hiding.
214
 
            var wrapper_div = Y.Node.create(
215
 
                '<div class="collapseWrapper" />');
216
 
 
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);
222
 
 
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');
234
 
            }
235
 
 
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);
240
 
 
241
 
            // If the collapsible is to be collapsed on pageload, do
242
 
            // so.
243
 
            if (collapsible.hasClass('collapsed')) {
244
 
                // Strip out the 'collapsed' class as it's no longer
245
 
                // needed.
246
 
                collapsible.removeClass('collapsed');
247
 
 
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);
253
 
                slide_in.run();
254
 
 
255
 
                icon.set('src', '/@@/treeCollapsed');
256
 
            }
257
 
 
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);
262
 
            });
263
 
        });
 
62
        // CSS selector 'legend + *' gets the next sibling element.
 
63
        Y.lp.app.widgets.expander.createByCSS(
 
64
            '.collapsible', 'legend', 'legend + *', true);
264
65
    };
 
66
 
265
67
    Y.lp.get_url_path = function(url) {
266
68
         return Y.Node.create('<a>junk</a>').set('href', url).get('pathname');
267
69
    };
268
 
}, "0.1", {"requires":["cookie", "lazr.effects"]});
 
70
}, "0.1", {"requires":["cookie", "lazr.effects", "lp.app.widgets.expander"]});
269
71
 
270
72
 
271
73
// Lint-safe scripting URL.
283
85
    });
284
86
}
285
87
 
286
 
function toggleExpandableTableRow(element_id) {
287
 
    var row = document.getElementById(element_id);
288
 
    var view_icon = document.getElementById(element_id + "-arrow");
289
 
    if (row.style.display == "table-row") {
290
 
      row.style.display = "none";
291
 
      view_icon.setAttribute("src", "/@@/treeCollapsed");
292
 
    } else {
293
 
      row.style.display = "table-row";
294
 
      view_icon.setAttribute("src", "/@@/treeExpanded");
295
 
    }
296
 
    return false;
297
 
}
298
 
 
299
 
function toggleExpandableTableRows(class_name) {
300
 
    var view_icon = document.getElementById(class_name + "-arrow");
301
 
    var all_page_tags = document.getElementsByTagName("*");
302
 
    for (i = 0; i < all_page_tags.length; i++) {
303
 
        row = all_page_tags[i];
304
 
        if (row.className == class_name) {
305
 
            if (row.style.display == "table-row") {
306
 
              row.style.display = "none";
307
 
              view_icon.setAttribute("src", "/@@/treeCollapsed");
308
 
            } else {
309
 
              row.style.display = "table-row";
310
 
              view_icon.setAttribute("src", "/@@/treeExpanded");
311
 
            }
312
 
        }
313
 
    }
314
 
    return false;
315
 
}
316
 
 
317
88
// Enable or disable the beta.launchpad.net redirect
318
89
function setBetaRedirect(enable) {
319
90
    var expire = new Date();