Mercurial > hg > cmmr2012-drupal-site
comparison core/misc/vertical-tabs.es6.js @ 4:a9cd425dd02b
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:11:55 +0000 |
parents | c75dbcec494b |
children |
comparison
equal
deleted
inserted
replaced
3:307d7a7fd348 | 4:a9cd425dd02b |
---|---|
10 * are the important fields' values. | 10 * are the important fields' values. |
11 * | 11 * |
12 * @event summaryUpdated | 12 * @event summaryUpdated |
13 */ | 13 */ |
14 | 14 |
15 (function ($, Drupal, drupalSettings) { | 15 (function($, Drupal, drupalSettings) { |
16 /** | 16 /** |
17 * Show the parent vertical tab pane of a targeted page fragment. | 17 * Show the parent vertical tab pane of a targeted page fragment. |
18 * | 18 * |
19 * In order to make sure a targeted element inside a vertical tab pane is | 19 * In order to make sure a targeted element inside a vertical tab pane is |
20 * visible on a hash change or fragment link click, show all parent panes. | 20 * visible on a hash change or fragment link click, show all parent panes. |
24 * @param {jQuery} $target | 24 * @param {jQuery} $target |
25 * The targeted node as a jQuery object. | 25 * The targeted node as a jQuery object. |
26 */ | 26 */ |
27 const handleFragmentLinkClickOrHashChange = (e, $target) => { | 27 const handleFragmentLinkClickOrHashChange = (e, $target) => { |
28 $target.parents('.vertical-tabs__pane').each((index, pane) => { | 28 $target.parents('.vertical-tabs__pane').each((index, pane) => { |
29 $(pane).data('verticalTab').focus(); | 29 $(pane) |
30 .data('verticalTab') | |
31 .focus(); | |
30 }); | 32 }); |
31 }; | 33 }; |
32 | 34 |
33 /** | 35 /** |
34 * This script transforms a set of details into a stack of vertical tabs. | 36 * This script transforms a set of details into a stack of vertical tabs. |
54 } | 56 } |
55 | 57 |
56 /** | 58 /** |
57 * Binds a listener to handle fragment link clicks and URL hash changes. | 59 * Binds a listener to handle fragment link clicks and URL hash changes. |
58 */ | 60 */ |
59 $('body').once('vertical-tabs-fragments').on('formFragmentLinkClickOrHashChange.verticalTabs', handleFragmentLinkClickOrHashChange); | 61 $('body') |
60 | 62 .once('vertical-tabs-fragments') |
61 $(context).find('[data-vertical-tabs-panes]').once('vertical-tabs').each(function () { | 63 .on( |
62 const $this = $(this).addClass('vertical-tabs__panes'); | 64 'formFragmentLinkClickOrHashChange.verticalTabs', |
63 const focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); | 65 handleFragmentLinkClickOrHashChange, |
64 let tabFocus; | 66 ); |
65 | 67 |
66 // Check if there are some details that can be converted to | 68 $(context) |
67 // vertical-tabs. | 69 .find('[data-vertical-tabs-panes]') |
68 const $details = $this.find('> details'); | 70 .once('vertical-tabs') |
69 if ($details.length === 0) { | 71 .each(function() { |
70 return; | 72 const $this = $(this).addClass('vertical-tabs__panes'); |
71 } | 73 const focusID = $this.find(':hidden.vertical-tabs__active-tab').val(); |
72 | 74 let tabFocus; |
73 // Create the tab column. | 75 |
74 const tabList = $('<ul class="vertical-tabs__menu"></ul>'); | 76 // Check if there are some details that can be converted to |
75 $this.wrap('<div class="vertical-tabs clearfix"></div>').before(tabList); | 77 // vertical-tabs. |
76 | 78 const $details = $this.find('> details'); |
77 // Transform each details into a tab. | 79 if ($details.length === 0) { |
78 $details.each(function () { | 80 return; |
79 const $that = $(this); | 81 } |
80 const verticalTab = new Drupal.verticalTab({ | 82 |
81 title: $that.find('> summary').text(), | 83 // Create the tab column. |
82 details: $that, | 84 const tabList = $('<ul class="vertical-tabs__menu"></ul>'); |
85 $this | |
86 .wrap('<div class="vertical-tabs clearfix"></div>') | |
87 .before(tabList); | |
88 | |
89 // Transform each details into a tab. | |
90 $details.each(function() { | |
91 const $that = $(this); | |
92 const verticalTab = new Drupal.verticalTab({ | |
93 title: $that.find('> summary').text(), | |
94 details: $that, | |
95 }); | |
96 tabList.append(verticalTab.item); | |
97 $that | |
98 .removeClass('collapsed') | |
99 // prop() can't be used on browsers not supporting details element, | |
100 // the style won't apply to them if prop() is used. | |
101 .attr('open', true) | |
102 .addClass('vertical-tabs__pane') | |
103 .data('verticalTab', verticalTab); | |
104 if (this.id === focusID) { | |
105 tabFocus = $that; | |
106 } | |
83 }); | 107 }); |
84 tabList.append(verticalTab.item); | 108 |
85 $that | 109 $(tabList) |
86 .removeClass('collapsed') | 110 .find('> li') |
87 // prop() can't be used on browsers not supporting details element, | 111 .eq(0) |
88 // the style won't apply to them if prop() is used. | 112 .addClass('first'); |
89 .attr('open', true) | 113 $(tabList) |
90 .addClass('vertical-tabs__pane') | 114 .find('> li') |
91 .data('verticalTab', verticalTab); | 115 .eq(-1) |
92 if (this.id === focusID) { | 116 .addClass('last'); |
93 tabFocus = $that; | 117 |
118 if (!tabFocus) { | |
119 // If the current URL has a fragment and one of the tabs contains an | |
120 // element that matches the URL fragment, activate that tab. | |
121 const $locationHash = $this.find(window.location.hash); | |
122 if (window.location.hash && $locationHash.length) { | |
123 tabFocus = $locationHash.closest('.vertical-tabs__pane'); | |
124 } else { | |
125 tabFocus = $this.find('> .vertical-tabs__pane').eq(0); | |
126 } | |
127 } | |
128 if (tabFocus.length) { | |
129 tabFocus.data('verticalTab').focus(); | |
94 } | 130 } |
95 }); | 131 }); |
96 | |
97 $(tabList).find('> li').eq(0).addClass('first'); | |
98 $(tabList).find('> li').eq(-1).addClass('last'); | |
99 | |
100 if (!tabFocus) { | |
101 // If the current URL has a fragment and one of the tabs contains an | |
102 // element that matches the URL fragment, activate that tab. | |
103 const $locationHash = $this.find(window.location.hash); | |
104 if (window.location.hash && $locationHash.length) { | |
105 tabFocus = $locationHash.closest('.vertical-tabs__pane'); | |
106 } | |
107 else { | |
108 tabFocus = $this.find('> .vertical-tabs__pane').eq(0); | |
109 } | |
110 } | |
111 if (tabFocus.length) { | |
112 tabFocus.data('verticalTab').focus(); | |
113 } | |
114 }); | |
115 }, | 132 }, |
116 }; | 133 }; |
117 | 134 |
118 /** | 135 /** |
119 * The vertical tab object represents a single tab within a tab group. | 136 * The vertical tab object represents a single tab within a tab group. |
129 * | 146 * |
130 * @fires event:summaryUpdated | 147 * @fires event:summaryUpdated |
131 * | 148 * |
132 * @listens event:summaryUpdated | 149 * @listens event:summaryUpdated |
133 */ | 150 */ |
134 Drupal.verticalTab = function (settings) { | 151 Drupal.verticalTab = function(settings) { |
135 const self = this; | 152 const self = this; |
136 $.extend(this, settings, Drupal.theme('verticalTab', settings)); | 153 $.extend(this, settings, Drupal.theme('verticalTab', settings)); |
137 | 154 |
138 this.link.attr('href', `#${settings.details.attr('id')}`); | 155 this.link.attr('href', `#${settings.details.attr('id')}`); |
139 | 156 |
140 this.link.on('click', (e) => { | 157 this.link.on('click', e => { |
141 e.preventDefault(); | 158 e.preventDefault(); |
142 self.focus(); | 159 self.focus(); |
143 }); | 160 }); |
144 | 161 |
145 // Keyboard events added: | 162 // Keyboard events added: |
146 // Pressing the Enter key will open the tab pane. | 163 // Pressing the Enter key will open the tab pane. |
147 this.link.on('keydown', (event) => { | 164 this.link.on('keydown', event => { |
148 if (event.keyCode === 13) { | 165 if (event.keyCode === 13) { |
149 event.preventDefault(); | 166 event.preventDefault(); |
150 self.focus(); | 167 self.focus(); |
151 // Set focus on the first input field of the visible details/tab pane. | 168 // Set focus on the first input field of the visible details/tab pane. |
152 $('.vertical-tabs__pane :input:visible:enabled').eq(0).trigger('focus'); | 169 $('.vertical-tabs__pane :input:visible:enabled') |
170 .eq(0) | |
171 .trigger('focus'); | |
153 } | 172 } |
154 }); | 173 }); |
155 | 174 |
156 this.details | 175 this.details |
157 .on('summaryUpdated', () => { | 176 .on('summaryUpdated', () => { |
159 }) | 178 }) |
160 .trigger('summaryUpdated'); | 179 .trigger('summaryUpdated'); |
161 }; | 180 }; |
162 | 181 |
163 Drupal.verticalTab.prototype = { | 182 Drupal.verticalTab.prototype = { |
164 | |
165 /** | 183 /** |
166 * Displays the tab's content pane. | 184 * Displays the tab's content pane. |
167 */ | 185 */ |
168 focus() { | 186 focus() { |
169 this.details | 187 this.details |
170 .siblings('.vertical-tabs__pane') | 188 .siblings('.vertical-tabs__pane') |
171 .each(function () { | 189 .each(function() { |
172 const tab = $(this).data('verticalTab'); | 190 const tab = $(this).data('verticalTab'); |
173 tab.details.hide(); | 191 tab.details.hide(); |
174 tab.item.removeClass('is-selected'); | 192 tab.item.removeClass('is-selected'); |
175 }) | 193 }) |
176 .end() | 194 .end() |
178 .siblings(':hidden.vertical-tabs__active-tab') | 196 .siblings(':hidden.vertical-tabs__active-tab') |
179 .val(this.details.attr('id')); | 197 .val(this.details.attr('id')); |
180 this.item.addClass('is-selected'); | 198 this.item.addClass('is-selected'); |
181 // Mark the active tab for screen readers. | 199 // Mark the active tab for screen readers. |
182 $('#active-vertical-tab').remove(); | 200 $('#active-vertical-tab').remove(); |
183 this.link.append(`<span id="active-vertical-tab" class="visually-hidden">${Drupal.t('(active tab)')}</span>`); | 201 this.link.append( |
202 `<span id="active-vertical-tab" class="visually-hidden">${Drupal.t( | |
203 '(active tab)', | |
204 )}</span>`, | |
205 ); | |
184 }, | 206 }, |
185 | 207 |
186 /** | 208 /** |
187 * Updates the tab's summary. | 209 * Updates the tab's summary. |
188 */ | 210 */ |
238 .eq(0) | 260 .eq(0) |
239 .addClass('first'); | 261 .addClass('first'); |
240 // Hide the details element. | 262 // Hide the details element. |
241 this.details.addClass('vertical-tab--hidden').hide(); | 263 this.details.addClass('vertical-tab--hidden').hide(); |
242 // Focus the first visible tab (if there is one). | 264 // Focus the first visible tab (if there is one). |
243 const $firstTab = this.details.siblings('.vertical-tabs__pane:not(.vertical-tab--hidden)').eq(0); | 265 const $firstTab = this.details |
266 .siblings('.vertical-tabs__pane:not(.vertical-tab--hidden)') | |
267 .eq(0); | |
244 if ($firstTab.length) { | 268 if ($firstTab.length) { |
245 $firstTab.data('verticalTab').focus(); | 269 $firstTab.data('verticalTab').focus(); |
246 } | 270 } |
247 // Hide the vertical tabs (if no tabs remain). | 271 // Hide the vertical tabs (if no tabs remain). |
248 else { | 272 else { |
265 * - item: The root tab jQuery element | 289 * - item: The root tab jQuery element |
266 * - link: The anchor tag that acts as the clickable area of the tab | 290 * - link: The anchor tag that acts as the clickable area of the tab |
267 * (jQuery version) | 291 * (jQuery version) |
268 * - summary: The jQuery element that contains the tab summary | 292 * - summary: The jQuery element that contains the tab summary |
269 */ | 293 */ |
270 Drupal.theme.verticalTab = function (settings) { | 294 Drupal.theme.verticalTab = function(settings) { |
271 const tab = {}; | 295 const tab = {}; |
272 tab.item = $('<li class="vertical-tabs__menu-item" tabindex="-1"></li>') | 296 tab.item = $( |
273 .append(tab.link = $('<a href="#"></a>') | 297 '<li class="vertical-tabs__menu-item" tabindex="-1"></li>', |
274 .append(tab.title = $('<strong class="vertical-tabs__menu-item-title"></strong>').text(settings.title)) | 298 ).append( |
275 .append(tab.summary = $('<span class="vertical-tabs__menu-item-summary"></span>'), | 299 (tab.link = $('<a href="#"></a>') |
276 ), | 300 .append( |
277 ); | 301 (tab.title = $( |
302 '<strong class="vertical-tabs__menu-item-title"></strong>', | |
303 ).text(settings.title)), | |
304 ) | |
305 .append( | |
306 (tab.summary = $( | |
307 '<span class="vertical-tabs__menu-item-summary"></span>', | |
308 )), | |
309 )), | |
310 ); | |
278 return tab; | 311 return tab; |
279 }; | 312 }; |
280 }(jQuery, Drupal, drupalSettings)); | 313 })(jQuery, Drupal, drupalSettings); |