|
1 |
|
2 (function ($) { |
|
3 |
|
4 /** |
|
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 |
|
7 * tab. |
|
8 * |
|
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. |
|
14 */ |
|
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(); |
|
19 var tab_focus; |
|
20 |
|
21 // Check if there are some fieldsets that can be converted to vertical-tabs |
|
22 var $fieldsets = $('> fieldset', this); |
|
23 if ($fieldsets.length == 0) { |
|
24 return; |
|
25 } |
|
26 |
|
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); |
|
30 |
|
31 // Transform each fieldset into a tab. |
|
32 $fieldsets.each(function () { |
|
33 var vertical_tab = new Drupal.verticalTab({ |
|
34 title: $('> legend', this).text(), |
|
35 fieldset: $(this) |
|
36 }); |
|
37 tab_list.append(vertical_tab.item); |
|
38 $(this) |
|
39 .removeClass('collapsible collapsed') |
|
40 .addClass('vertical-tabs-pane') |
|
41 .data('verticalTab', vertical_tab); |
|
42 if (this.id == focusID) { |
|
43 tab_focus = $(this); |
|
44 } |
|
45 }); |
|
46 |
|
47 $('> li:first', tab_list).addClass('first'); |
|
48 $('> li:last', tab_list).addClass('last'); |
|
49 |
|
50 if (!tab_focus) { |
|
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 && $(this).find(window.location.hash).length) { |
|
54 tab_focus = $(this).find(window.location.hash).closest('.vertical-tabs-pane'); |
|
55 } |
|
56 else { |
|
57 tab_focus = $('> .vertical-tabs-pane:first', this); |
|
58 } |
|
59 } |
|
60 if (tab_focus.length) { |
|
61 tab_focus.data('verticalTab').focus(); |
|
62 } |
|
63 }); |
|
64 } |
|
65 }; |
|
66 |
|
67 /** |
|
68 * The vertical tab object represents a single tab within a tab group. |
|
69 * |
|
70 * @param settings |
|
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. |
|
74 */ |
|
75 Drupal.verticalTab = function (settings) { |
|
76 var self = this; |
|
77 $.extend(this, settings, Drupal.theme('verticalTab', settings)); |
|
78 |
|
79 this.link.click(function () { |
|
80 self.focus(); |
|
81 return false; |
|
82 }); |
|
83 |
|
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) { |
|
88 self.focus(); |
|
89 // Set focus on the first input field of the visible fieldset/tab pane. |
|
90 $("fieldset.vertical-tabs-pane :input:visible:enabled:first").focus(); |
|
91 return false; |
|
92 } |
|
93 }); |
|
94 |
|
95 this.fieldset |
|
96 .bind('summaryUpdated', function () { |
|
97 self.updateSummary(); |
|
98 }) |
|
99 .trigger('summaryUpdated'); |
|
100 }; |
|
101 |
|
102 Drupal.verticalTab.prototype = { |
|
103 /** |
|
104 * Displays the tab's content pane. |
|
105 */ |
|
106 focus: function () { |
|
107 this.fieldset |
|
108 .siblings('fieldset.vertical-tabs-pane') |
|
109 .each(function () { |
|
110 var tab = $(this).data('verticalTab'); |
|
111 tab.fieldset.hide(); |
|
112 tab.item.removeClass('selected'); |
|
113 }) |
|
114 .end() |
|
115 .show() |
|
116 .siblings(':hidden.vertical-tabs-active-tab') |
|
117 .val(this.fieldset.attr('id')); |
|
118 this.item.addClass('selected'); |
|
119 // Mark the active tab for screen readers. |
|
120 $('#active-vertical-tab').remove(); |
|
121 this.link.append('<span id="active-vertical-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>'); |
|
122 }, |
|
123 |
|
124 /** |
|
125 * Updates the tab's summary. |
|
126 */ |
|
127 updateSummary: function () { |
|
128 this.summary.html(this.fieldset.drupalGetSummary()); |
|
129 }, |
|
130 |
|
131 /** |
|
132 * Shows a vertical tab pane. |
|
133 */ |
|
134 tabShow: function () { |
|
135 // Display the tab. |
|
136 this.item.show(); |
|
137 // Show the vertical tabs. |
|
138 this.item.closest('.vertical-tabs').show(); |
|
139 // Update .first marker for items. We need recurse from parent to retain the |
|
140 // actual DOM element order as jQuery implements sortOrder, but not as public |
|
141 // method. |
|
142 this.item.parent().children('.vertical-tab-button').removeClass('first') |
|
143 .filter(':visible:first').addClass('first'); |
|
144 // Display the fieldset. |
|
145 this.fieldset.removeClass('vertical-tab-hidden').show(); |
|
146 // Focus this tab. |
|
147 this.focus(); |
|
148 return this; |
|
149 }, |
|
150 |
|
151 /** |
|
152 * Hides a vertical tab pane. |
|
153 */ |
|
154 tabHide: function () { |
|
155 // Hide this tab. |
|
156 this.item.hide(); |
|
157 // Update .first marker for items. We need recurse from parent to retain the |
|
158 // actual DOM element order as jQuery implements sortOrder, but not as public |
|
159 // method. |
|
160 this.item.parent().children('.vertical-tab-button').removeClass('first') |
|
161 .filter(':visible:first').addClass('first'); |
|
162 // Hide the fieldset. |
|
163 this.fieldset.addClass('vertical-tab-hidden').hide(); |
|
164 // Focus the first visible tab (if there is one). |
|
165 var $firstTab = this.fieldset.siblings('.vertical-tabs-pane:not(.vertical-tab-hidden):first'); |
|
166 if ($firstTab.length) { |
|
167 $firstTab.data('verticalTab').focus(); |
|
168 } |
|
169 // Hide the vertical tabs (if no tabs remain). |
|
170 else { |
|
171 this.item.closest('.vertical-tabs').hide(); |
|
172 } |
|
173 return this; |
|
174 } |
|
175 }; |
|
176 |
|
177 /** |
|
178 * Theme function for a vertical tab. |
|
179 * |
|
180 * @param settings |
|
181 * An object with the following keys: |
|
182 * - title: The name of the tab. |
|
183 * @return |
|
184 * This function has to return an object with at least these keys: |
|
185 * - item: The root tab jQuery element |
|
186 * - link: The anchor tag that acts as the clickable area of the tab |
|
187 * (jQuery version) |
|
188 * - summary: The jQuery element that contains the tab summary |
|
189 */ |
|
190 Drupal.theme.prototype.verticalTab = function (settings) { |
|
191 var tab = {}; |
|
192 tab.item = $('<li class="vertical-tab-button" tabindex="-1"></li>') |
|
193 .append(tab.link = $('<a href="#"></a>') |
|
194 .append(tab.title = $('<strong></strong>').text(settings.title)) |
|
195 .append(tab.summary = $('<span class="summary"></span>') |
|
196 ) |
|
197 ); |
|
198 return tab; |
|
199 }; |
|
200 |
|
201 })(jQuery); |