5a920362 |
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 && $(window.location.hash, this).length) { |
54 | tab_focus = $(window.location.hash, this).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 | // 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(); |
101 | return false; |
102 | } |
103 | }); |
104 | |
105 | this.fieldset |
106 | .bind('summaryUpdated', function () { |
107 | self.updateSummary(); |
108 | }) |
109 | .trigger('summaryUpdated'); |
110 | }; |
111 | |
112 | Drupal.verticalTab.prototype = { |
113 | /** |
114 | * Displays the tab's content pane. |
115 | */ |
116 | focus: function () { |
117 | this.fieldset |
118 | .siblings('fieldset.vertical-tabs-pane') |
119 | .each(function () { |
120 | var tab = $(this).data('verticalTab'); |
121 | tab.fieldset.hide(); |
122 | tab.item.removeClass('selected'); |
123 | }) |
124 | .end() |
125 | .show() |
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>'); |
132 | }, |
133 | |
134 | /** |
135 | * Updates the tab's summary. |
136 | */ |
137 | updateSummary: function () { |
138 | this.summary.html(this.fieldset.drupalGetSummary()); |
139 | }, |
140 | |
141 | /** |
142 | * Shows a vertical tab pane. |
143 | */ |
144 | tabShow: function () { |
145 | // Display the tab. |
146 | this.item.show(); |
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 |
149 | // method. |
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(); |
154 | // Focus this tab. |
155 | this.focus(); |
156 | return this; |
157 | }, |
158 | |
159 | /** |
160 | * Hides a vertical tab pane. |
161 | */ |
162 | tabHide: function () { |
163 | // Hide this tab. |
164 | this.item.hide(); |
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 |
167 | // method. |
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(); |
176 | } |
177 | return this; |
178 | } |
179 | }; |
180 | |
181 | /** |
182 | * Theme function for a vertical tab. |
183 | * |
184 | * @param settings |
185 | * An object with the following keys: |
186 | * - title: The name of the tab. |
187 | * @return |
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 |
191 | * (jQuery version) |
192 | * - summary: The jQuery element that contains the tab summary |
193 | */ |
194 | Drupal.theme.prototype.verticalTab = function (settings) { |
195 | var tab = {}; |
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>') |
200 | ) |
201 | ); |
202 | return tab; |
203 | }; |
204 | |
205 | })(jQuery); |