82dcd2c62ed91343ef8ceee1e29424e9bfc4f8f6
5 * This script transforms a set of fieldsets into a stack of vertical
6 * tabs. Another tab pane can be selected by clicking on the respective
9 * Each tab may have a summary which can be updated by another
10 * script. For that to work, each fieldset has an associated
11 * 'verticalTabCallback' (with jQuery.data() attached to the fieldset),
12 * which is called every time the user performs an update to a form
13 * element inside the tab pane.
15 Drupal
.behaviors
.verticalTabs
= {
16 attach: function (context
) {
17 $('.vertical-tabs-panes', context
).once('vertical-tabs', function () {
18 var focusID
= $(':hidden.vertical-tabs-active-tab', this).val();
21 // Check if there are some fieldsets that can be converted to vertical-tabs
22 var $fieldsets
= $('> fieldset', this);
23 if ($fieldsets
.length
== 0) {
27 // Create the tab column.
28 var tab_list
= $('<ul class="vertical-tabs-list"></ul>');
29 $(this).wrap('<div class="vertical-tabs clearfix"></div>').before(tab_list
);
31 // Transform each fieldset into a tab.
32 $fieldsets
.each(function () {
33 var vertical_tab
= new Drupal
.verticalTab({
34 title
: $('> legend', this).text(),
37 tab_list
.append(vertical_tab
.item
);
39 .removeClass('collapsible collapsed')
40 .addClass('vertical-tabs-pane')
41 .data('verticalTab', vertical_tab
);
42 if (this.id
== focusID
) {
47 $('> li:first', tab_list
).addClass('first');
48 $('> li:last', tab_list
).addClass('last');
51 // If the current URL has a fragment and one of the tabs contains an
52 // element that matches the URL fragment, activate that tab.
53 if (window
.location
.hash
&& $(window
.location
.hash
, this).length
) {
54 tab_focus
= $(window
.location
.hash
, this).closest('.vertical-tabs-pane');
57 tab_focus
= $('> .vertical-tabs-pane:first', this);
60 if (tab_focus
.length
) {
61 tab_focus
.data('verticalTab').focus();
68 * The vertical tab object represents a single tab within a tab group.
71 * An object with the following keys:
72 * - title: The name of the tab.
73 * - fieldset: The jQuery object of the fieldset that is the tab pane.
75 Drupal
.verticalTab = function (settings
) {
77 $.extend(this, settings
, Drupal
.theme('verticalTab', settings
));
79 this.link
.click(function () {
84 // Keyboard events added:
85 // Pressing the Enter key will open the tab pane.
86 this.link
.keydown(function(event
) {
87 if (event
.keyCode
== 13) {
89 // Set focus on the first input field of the visible fieldset/tab pane.
90 $("fieldset.vertical-tabs-pane :input:visible:enabled:first").focus();
95 // Pressing the Enter key lets you leave the tab again.
96 this.fieldset
.keydown(function(event
) {
97 // Enter key should not trigger inside <textarea> to allow for multi-line entries.
98 if (event
.keyCode
== 13 && event
.target
.nodeName
!= "TEXTAREA") {
99 // Set focus on the selected tab button again.
100 $(".vertical-tab-button.selected a").focus();
106 .bind('summaryUpdated', function () {
107 self
.updateSummary();
109 .trigger('summaryUpdated');
112 Drupal
.verticalTab
.prototype = {
114 * Displays the tab's content pane.
118 .siblings('fieldset.vertical-tabs-pane')
120 var tab
= $(this).data('verticalTab');
122 tab
.item
.removeClass('selected');
126 .siblings(':hidden.vertical-tabs-active-tab')
127 .val(this.fieldset
.attr('id'));
128 this.item
.addClass('selected');
129 // Mark the active tab for screen readers.
130 $('#active-vertical-tab').remove();
131 this.link
.append('<span id="active-vertical-tab" class="element-invisible">' + Drupal
.t('(active tab)') + '</span>');
135 * Updates the tab's summary.
137 updateSummary: function () {
138 this.summary
.html(this.fieldset
.drupalGetSummary());
142 * Shows a vertical tab pane.
144 tabShow: function () {
147 // Update .first marker for items. We need recurse from parent to retain the
148 // actual DOM element order as jQuery implements sortOrder, but not as public
150 this.item
.parent().children('.vertical-tab-button').removeClass('first')
151 .filter(':visible:first').addClass('first');
152 // Display the fieldset.
153 this.fieldset
.removeClass('vertical-tab-hidden').show();
160 * Hides a vertical tab pane.
162 tabHide: function () {
165 // Update .first marker for items. We need recurse from parent to retain the
166 // actual DOM element order as jQuery implements sortOrder, but not as public
168 this.item
.parent().children('.vertical-tab-button').removeClass('first')
169 .filter(':visible:first').addClass('first');
170 // Hide the fieldset.
171 this.fieldset
.addClass('vertical-tab-hidden').hide();
172 // Focus the first visible tab (if there is one).
173 var $firstTab
= this.fieldset
.siblings('.vertical-tabs-pane:not(.vertical-tab-hidden):first');
174 if ($firstTab
.length
) {
175 $firstTab
.data('verticalTab').focus();
182 * Theme function for a vertical tab.
185 * An object with the following keys:
186 * - title: The name of the tab.
188 * This function has to return an object with at least these keys:
189 * - item: The root tab jQuery element
190 * - link: The anchor tag that acts as the clickable area of the tab
192 * - summary: The jQuery element that contains the tab summary
194 Drupal
.theme
.prototype.verticalTab = function (settings
) {
196 tab
.item
= $('<li class="vertical-tab-button" tabindex="-1"></li>')
197 .append(tab
.link
= $('<a href="#"></a>')
198 .append(tab
.title
= $('<strong></strong>').text(settings
.title
))
199 .append(tab
.summary
= $('<span class="summary"></span>')