PluginProbe
LWS Tools / trunk
LWS Tools vtrunk
trunk 1.0 1.0.1 2.0 2.1 2.1.5 2.2 2.2.1 2.3 2.3.1 2.4 2.4.1 2.4.2 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5 2.6 2.6.1 2.6.1.5 2.6.2 2.6.3 2.6.4
lws-tools / view / tabs.php

tabs.php in LWS Tools trunk, at view/tabs.php

540 lines 24.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 $arr = array('strong' => array());
3
4 $plugins = array(
5 'lws-hide-login' => array('LWS Hide Login', __('This plugin <strong>hide your administration page</strong> (wp-admin) and lets you <strong>change your login page</strong> (wp-login). It offers better security as hackers will have more trouble finding the page.', 'lws-tools'), true),
6 'lws-optimize' => array('LWS Optimize', __("This plugin lets you boost your website's <strong>loading times</strong> thanks to our tools: caching, media optimisation, files minification and concatenation...", 'lws-tools'), true),
7 'lws-cleaner' => array('LWS Cleaner', __('This plugin lets you <strong>clean your WordPress website</strong> in a few clics to gain speed: posts, comments, terms, users, settings, plugins, medias, files.', 'lws-tools'), true),
8 // 'lws-sms' => array('LWS SMS', __('This plugin, designed specifically for WooCommerce, lets you <strong>send SMS automatically to your customers</strong>. You will need an account at LWS and enough credits to send SMS. Create personnalized templates, manage your SMS and sender IDs and more!', 'lws-tools'), false),
9 'lws-affiliation' => array('LWS Affiliation', __('With this plugin, you can add banners and widgets on your website and use those with your <strong>affiliate account LWS</strong>. Earn money and follow the evolution of your gains on your website.', 'lws-tools'), false),
10 'lwscache' => array('LWSCache', __('Based on the Varnich cache technology and NGINX, LWSCache let you <strong>speed up the loading of your pages</strong>. This plugin helps you automatically manage your LWSCache when editing pages, posts... and purging all your cache. Works only if your server use this cache.', 'lws-tools'), false),
11 'lws-tools' => array('LWS Tools', __('This plugin provides you with several tools and shortcuts to manage, secure and optimise your WordPress website. Updating plugins and themes, accessing informations about your server, managing your website parameters, etc... Personnalize every aspect of your website!', 'lws-tools'), false)
12 );
13
14 $plugins_activated = array();
15 $all_plugins = get_plugins();
16
17 foreach ($plugins as $slug => $plugin) {
18 if (is_plugin_active($slug . '/' . $slug . '.php')) {
19 $plugins_activated[$slug] = "full";
20 } elseif (array_key_exists($slug . '/' . $slug . '.php', $all_plugins)) {
21 $plugins_activated[$slug] = "half";
22 }
23 }
24
25 $tabs_list = array(
26 array('notifications', __('Notifications', 'lws-tools')),
27 array('server', __('Server', 'lws-tools')),
28 array('optimisation', __('Optimisations', 'lws-tools')),
29 array('security', __('Security', 'lws-tools')),
30 //array('antivirus', __('Antivirus', 'lws-tools')),
31 array('mysql', __('MySQL Logs', 'lws-tools')),
32 array('tools', __('Other Tools', 'lws-tools')),
33 array('ia', __('WPilot (AI Assistant)', 'lws-tools')),
34 array('plugins', __('Our plugins', 'lws-tools')),
35 )
36 // // //
37 ?>
38
39 <script>
40 var function_ok = true;
41 </script>
42
43 <!-- Beginning main content block -->
44 <div class="lws_tk_main_bloc">
45
46 <div class="lwstk_title_banner">
47 <div class="lwstk_top_banner">
48 <img src="<?php echo esc_url(plugins_url('images/plugin_lws_tools_logo.svg', __DIR__)) ?>" alt="LWS Tools Logo" width="80px" height="80px">
49 <div class="lwstk_top_banner_text">
50 <div class="lwstk_top_title_block">
51 <div style="display: flex; flex-direction: column; gap: 15px;">
52 <div class="lwstk_top_title">
53 <span><?php echo esc_html('LWS Tools'); ?></span>
54 <span><?php esc_html_e('by', 'lws-tools'); ?></span>
55 <span class="logo_lws"></span>
56 </div>
57
58 <div class="lwstk_top_description">
59 <?php echo esc_html_e('LWS Tools offer toolkits and shortcuts to manage your WordPress website. It lets you secure and optimize your websites easily and visualize several useful informations about your server, website and database.', 'lws-tools'); ?>
60 </div>
61 </div>
62 <div class="lwstk_rate_block">
63 <div class="lwstk_top_rateus">
64 <?php echo esc_html_e('You like this plugin ? ', 'lws-tools'); ?>
65 <?php echo wp_kses(__('A <a href="https://wordpress.org/support/plugin/lws-tools/reviews/#new-post" target="_blank" class="link_to_rating_with_stars"><div class="lwstk_stars">�
66 �
67 �
68 �
69 �
70 </div> rating</a> will motivate us a lot.', 'lws-tools'), ['a' => ['class' => [], 'href' => [], 'target' => []], 'div' => ['class' => []]]); ?>
71 </div>
72 <div class="lwstk_bottom_rateus">
73 <img src="<?php echo esc_url(plugins_url('images/flamme.svg', __DIR__)) ?>" alt="Flamme Logo" width="16px" height="20px" style="margin-right: 5px;">
74 <?php echo wp_kses(__('<b>-15%</b> on our <a href="https://www.lws.fr/hebergement_wordpress.php" target="_blank" class="link_to_support">WordPress hostings</a> with the code', 'lws-tools'), ['b' => [], 'a' => ['class' => [], 'href' => [], 'target' => []]]); ?>
75 <div class="lwstk_top_code">
76 WPEXT15
77 <img src="<?php echo esc_url(plugins_url('images/copier_new.svg', __DIR__)) ?>" alt="Logo Copy Element" width="15px" height="18px" onclick="lwstktimize_copy_clipboard(this)" readonly text="WPEXT15">
78 </div>
79 </div>
80 </div>
81 </div>
82 </div>
83 </div>
84 </div>
85
86
87
88 <!-- Home to the tabs + content + ads -->
89 <div class="lws_tk_main_content">
90
91 <!-- tabs + content -->
92 <div class="lws_tk_list_block_content">
93 <!-- Tabs -->
94 <div class="tab_lws_tk" id='tab_lws_tk_block'>
95 <div id="tab_lws_tk" role="tablist" aria-label="Onglets_lws_tk">
96 <?php foreach ($tabs_list as $tab) : ?>
97 <button
98 id="<?php echo esc_attr('nav-' . $tab[0]); ?>"
99 class="tab_nav_lws_tk <?php echo $tab[0] == 'notifications' ? esc_attr('active') : ''; ?>"
100 data-toggle="tab" role="tab"
101 aria-controls="<?php echo esc_attr($tab[0]);?>"
102 aria-selected="<?php echo $tab[0] == 'notifications' ? esc_attr('true') : esc_attr('false'); ?>"
103 tabindex="<?php echo $tab[0] == 'notifications' ? esc_attr('0') : '-1'; ?>">
104 <?php if ($tab[0] == "ia") : ?>
105 <img src="<?php echo esc_url(plugins_url('images/lws_ia.svg', __DIR__)) ?>" alt="IA Icon" width="20px" height="20px">
106 <?php endif; ?>
107 <?php echo esc_html($tab[1]); ?>
108 </button>
109 <?php endforeach ?>
110 <div id="selector" class="selector_tab">&nbsp;</div>
111 </div>
112
113 <div class="tab_lws_tk_select hidden">
114 <select name="tab_lws_tk_select" id="tab_lws_tk_select" style="text-align:center">
115 <?php foreach ($tabs_list as $tab) : ?>
116 <option
117 value="<?php echo esc_attr("nav-" . $tab[0]); ?>">
118 <?php echo esc_html($tab[1]); ?>
119 </option>
120 <?php endforeach?>
121 </select>
122 </div>
123 </div>
124
125 <?php foreach ($tabs_list as $tab) : ?>
126 <div class="tab-pane main-tab-pane"
127 id="<?php echo esc_attr($tab[0])?>" role="tabpanel"
128 aria-labelledby="nav-<?php echo esc_attr($tab[0])?>"
129 <?php echo $tab[0] == 'notifications' ? esc_attr('tabindex="0"') : esc_attr('tabindex="-1" hidden')?>>
130 <div id="post-body"
131 class="<?php echo $tab[0] == 'plugins' ? esc_attr('lws_tk_configpage_plugin') : esc_attr('lws_tk_configpage'); ?> ">
132 <?php include plugin_dir_path(__FILE__) . $tab[0] . '.php'; ?>
133 </div>
134 </div>
135 <?php endforeach?>
136 </div>
137 </div>
138 </div>
139
140 <div id="lws_tk_popup_alerting"></div>
141
142 <script>
143 function lws_tk_copy_clipboard(input) {
144 navigator.clipboard.writeText(input.innerText.trim());
145 setTimeout(function() {
146 jQuery('#copied_tip').remove();
147 }, 500);
148 jQuery(input).append("<div class='tip' id='copied_tip'>" +
149 "<?php esc_html_e('Copied!', 'lws-tools');?>" +
150 "</div>");
151 }
152
153 // Execute the function callback after ms milliseconds unless delay() is called again
154 function delay(callback, ms) {
155 var timer = 0;
156 return function() {
157 var context = this,
158 args = arguments;
159 clearTimeout(timer);
160 timer = setTimeout(function() {
161 callback.apply(context, args);
162 }, ms || 0);
163 };
164 }
165
166 function callPopup(type, content) {
167 // Get the element containing all popups
168 let alerting = document.getElementById('lws_tk_popup_alerting');
169 if (alerting == null) {
170 console.log(JSON.stringify({
171 'code': "POPUP_FAIL",
172 'data': "Failed to find alerting"
173 }));
174 return -1;
175 }
176
177 if (content == null) {
178 console.log(JSON.stringify({
179 'code': "POPUP_FAIL",
180 'data': "Failed to find content"
181 }));
182 return -1;
183 }
184
185 if (type == null) {
186 console.log(JSON.stringify({
187 'code': "POPUP_FAIL",
188 'data': "Failed to find type"
189 }));
190 return -1;
191 }
192
193 // No more than 4 popups at a time. Remove the oldest one
194 if (alerting.children.length > 4) {
195 let amount_popups = alerting.children;
196 let last = amount_popups.item(amount_popups.length - 1);
197 if (last != null) {
198 jQuery(last).animate({
199 'left': '150%'
200 }, 500, function() {
201 last.remove();
202 });
203 }
204 }
205
206 let number = alerting.children.length ?? 5;
207
208 alerting.insertAdjacentHTML('afterbegin', `<div class="lws_tk_information_popup" style="left: 150%;" id="lws_tk_information_popup_` + number + `"></div>`);
209 let popup = document.getElementById('lws_tk_information_popup_' + number);
210
211 if (popup == null) {
212 console.log(JSON.stringify({
213 'code': "POPUP_NOT_CREATED",
214 'data': "Failed to create the popup"
215 }));
216 return -1;
217 }
218
219 animation = ``;
220 switch (type) {
221 case 'success':
222 animation = `<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" /><path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" /></svg>`;
223 break;
224 case 'error':
225 animation = `
226 <svg class="crossmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"> <circle class="crossmark__circle" cx="26" cy="26" r="25" fill="none" stroke="red" stroke-width="2"></circle> <path class="crossmark__cross" fill="none" stroke="red" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="36" stroke-dashoffset="36" d="M16 16 36 36 M36 16 16 36"> <animate attributeName="stroke-dashoffset" from="36" to="0" dur="0.5s" fill="freeze" /> </path></svg>`
227 break;
228 case 'warning':
229 animation = `<svg class="exclamation" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"> <circle class="exclamation__circle" cx="26" cy="26" r="25" fill="none" stroke="#FFD700" stroke-width="2"></circle> <text class="exclamation__mark" x="26" y="30" font-size="26" font-family="Arial" text-anchor="middle" fill="#FFD700" dominant-baseline="middle">!</text> <style> .exclamation__mark { animation: blink 1s ease-in-out 3; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } </style> </svg>`;
230 break;
231 default:
232 animation = `<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" /><path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" /></svg>`;
233 break;
234 }
235
236 popup.insertAdjacentHTML('beforeend', `
237 <div class="lws_tk_information_popup_animation">` + animation + `</div>
238 <div class="lws_tk_information_popup_content">` + content + `</div>
239 <div id="lws_tk_close_popup_` + number + `" class="lws_tk_information_popup_close"><img src="<?php echo esc_url(plugins_url('images/fermer.svg', __DIR__)) ?>" alt="close button" width="10px" height="10px">
240 `)
241
242 jQuery(popup).animate({
243 'left': '0%'
244 }, 500);
245
246 popup.classList.add('popup_' + type);
247
248 let popup_button = document.getElementById('lws_tk_close_popup_' + number);
249 if (popup_button != null) {
250 popup_button.addEventListener('click', function() {
251 this.parentNode.remove();
252 })
253 }
254
255 popup.addEventListener('mouseover', delay(function() {
256 if (popup.matches(':hover')) {
257 return 0;
258 }
259 jQuery(this).animate({
260 'left': '150%'
261 }, 500, function() {
262 this.remove();
263 });
264 }, 5000));
265
266 popup.dispatchEvent(new Event('mouseover'));
267 }
268 </script>
269
270
271 <script>
272 var reset_table = (function() {
273 var executed_template = false;
274 return function() {
275 if (!executed_template && jQuery('#lws_tk_mysqltable') != null) {
276 executed_template = true;
277 jQuery(document).ready(function() {
278 jQuery('#lws_tk_mysqltable').DataTable().columns.adjust();
279 });
280 }
281 };
282 })();
283
284 jQuery(document).ready(function() {
285 <?php foreach ($plugins_activated as $slug => $activated) : ?>
286 <?php if ($activated == "full") : ?>
287
288 /**/
289 var button = jQuery(
290 "<?php echo esc_attr("#bis_" . $slug); ?>"
291 );
292 button.children()[3].classList.remove('hidden');
293 button.children()[0].classList.add('hidden');
294 button.prop('onclick', false);
295 button.addClass('lws_tk_button_ad_block_validated');
296
297 <?php elseif ($activated == "half") : ?>
298 /**/
299 var button = jQuery(
300 "<?php echo esc_attr("#bis_" . $slug); ?>"
301 );
302 button.children()[2].classList.remove('hidden');
303 button.children()[0].classList.add('hidden');
304 <?php endif ?>
305 <?php endforeach ?>
306 });
307
308 function install_plugin(button) {
309 var newthis = this;
310 if (this.function_ok) {
311 this.function_ok = false;
312 const regex = /bis_/;
313 bouton_id = button.id;
314 bouton_sec = "";
315 if (bouton_id.match(regex)) {
316 bouton_sec = bouton_id.substring(4);
317 } else {
318 bouton_sec = "bis_" + bouton_id;
319 }
320
321 button_sec = document.getElementById(bouton_sec);
322
323 button.children[0].classList.add('hidden');
324 button.children[3].classList.add('hidden');
325 button.children[2].classList.add('hidden');
326 button.children[1].classList.remove('hidden');
327 button.classList.remove('lws_tk_button_ad_block_validated');
328 button.setAttribute('disabled', true);
329
330 if (button_sec !== null) {
331 button_sec.children[0].classList.add('hidden');
332 button_sec.children[3].classList.add('hidden');
333 button_sec.children[2].classList.add('hidden');
334 button_sec.children[1].classList.remove('hidden');
335 button_sec.classList.remove('lws_tk_button_ad_block_validated');
336 button_sec.setAttribute('disabled', true);
337 }
338
339 var data = {
340 action: "lws_tk_downloadPlugin",
341 _ajax_nonce: '<?php echo esc_attr(wp_create_nonce('updates')); ?>',
342 slug: button.getAttribute('value'),
343 };
344 jQuery.post(ajaxurl, data, function(response) {
345 if (!response.success) {
346 if (response.data.errorCode == 'folder_exists') {
347 var data = {
348 action: "lws_tk_activatePlugin",
349 ajax_slug: response.data.slug,
350 _ajax_nonce: '<?php echo esc_attr(wp_create_nonce('tools_activate_plugin')); ?>',
351 };
352 jQuery.post(ajaxurl, data, function(response) {
353 jQuery('#' + bouton_id).children()[1].classList.add('hidden');
354 jQuery('#' + bouton_id).children()[2].classList.add('hidden');
355 jQuery('#' + bouton_id).children()[3].classList.remove('hidden');
356 jQuery('#' + bouton_id).addClass('lws_tk_button_ad_block_validated');
357 newthis.function_ok = true;
358
359 if (button_sec !== null) {
360 jQuery('#' + bouton_sec).children()[1].classList.add('hidden');
361 jQuery('#' + bouton_sec).children()[2].classList.add('hidden');
362 jQuery('#' + bouton_sec).children()[3].classList.remove('hidden');
363 jQuery('#' + bouton_sec).addClass(
364 'lws_tk_button_ad_block_validated');
365 newthis.function_ok = true;
366 }
367 });
368
369 } else {
370 jQuery('#' + bouton_id).children()[1].classList.add('hidden');
371 jQuery('#' + bouton_id).children()[2].classList.add('hidden');
372 jQuery('#' + bouton_id).children()[3].classList.add('hidden');
373 jQuery('#' + bouton_id).children()[0].classList.add('hidden');
374 jQuery('#' + bouton_id).children()[4].classList.remove('hidden');
375 jQuery('#' + bouton_id).addClass('lws_tk_button_ad_block_failed');
376 setTimeout(() => {
377 jQuery('#' + bouton_id).removeClass('lws_tk_button_ad_block_failed');
378 jQuery('#' + bouton_id).prop('disabled', false);
379 jQuery('#' + bouton_id).children()[0].classList.remove('hidden');
380 jQuery('#' + bouton_id).children()[4].classList.add('hidden');
381 newthis.function_ok = true;
382 }, 2500);
383
384 if (button_sec !== null) {
385 jQuery('#' + bouton_sec).children()[1].classList.add('hidden');
386 jQuery('#' + bouton_sec).children()[2].classList.add('hidden');
387 jQuery('#' + bouton_sec).children()[3].classList.add('hidden');
388 jQuery('#' + bouton_sec).children()[0].classList.add('hidden');
389 jQuery('#' + bouton_sec).children()[4].classList.remove('hidden');
390 jQuery('#' + bouton_sec).addClass('lws_tk_button_ad_block_failed');
391 setTimeout(() => {
392 jQuery('#' + bouton_sec).removeClass(
393 'lws_tk_button_ad_block_failed');
394 jQuery('#' + bouton_sec).prop('disabled', false);
395 jQuery('#' + bouton_sec).children()[0].classList.remove('hidden');
396 jQuery('#' + bouton_sec).children()[4].classList.add('hidden');
397 newthis.function_ok = true;
398 }, 2500);
399 }
400 }
401 } else {
402 jQuery('#' + bouton_id).children()[1].classList.add('hidden');
403 jQuery('#' + bouton_id).children()[2].classList.remove('hidden');
404 jQuery('#' + bouton_id).prop('disabled', false);
405 newthis.function_ok = true;
406
407 if (button_sec !== null) {
408 jQuery('#' + bouton_sec).children()[1].classList.add('hidden');
409 jQuery('#' + bouton_sec).children()[2].classList.remove('hidden');
410 jQuery('#' + bouton_sec).prop('disabled', false);
411 newthis.function_ok = true;
412 }
413 }
414 });
415 }
416 }
417 </script>
418
419 <!-- Here, need to change id of the selector and tabs -->
420 <script>
421 const tabs = document.querySelectorAll('.tab_nav_lws_tk[role="tab"]');
422
423 // Add a click event handler to each tab
424 tabs.forEach((tab) => {
425 tab.addEventListener('click', lws_tk_changeTabs);
426 });
427
428 <?php if (isset($change_tab)) : ?>
429 var element = document.getElementById(
430 "<?php echo esc_attr($change_tab); ?>");
431 lws_tk_changeTabs(element);
432 <?php else : ?>
433 lws_tk_selectorMove(document.getElementById('nav-notifications'), document.getElementById('nav-notifications').parentNode);
434 <?php endif ?>
435
436 function lws_tk_selectorMove(target, parent) {
437 const cursor = document.getElementById('selector');
438 var element = target.getBoundingClientRect();
439 var bloc = parent.getBoundingClientRect();
440
441 var padding = parseInt((window.getComputedStyle(target, null).getPropertyValue('padding-left')).slice(0, -
442 2));
443 var margin = parseInt((window.getComputedStyle(target, null).getPropertyValue('margin-left')).slice(0, -2));
444 var begin = (element.left - bloc.left) - margin;
445 var ending = target.clientWidth + 2 * margin;
446
447 cursor.style.width = ending + "px";
448 cursor.style.left = begin + "px";
449 }
450
451 function lws_tk_changeTabs(e) {
452 var target;
453 if (e.target === undefined) {
454 target = e;
455 } else {
456 target = e.target;
457 }
458 const parent = target.parentNode;
459 const grandparent = parent.parentNode.parentNode;
460
461 // Remove all current selected tabs
462 parent
463 .querySelectorAll('.tab_nav_lws_tk[aria-selected="true"]')
464 .forEach(function(t) {
465 t.setAttribute('aria-selected', false);
466 t.classList.remove("active")
467 });
468
469 // Set this tab as selected
470 target.setAttribute('aria-selected', true);
471 target.classList.add('active');
472
473 // Hide all tab panels
474 grandparent
475 .querySelectorAll('.tab-pane.main-tab-pane[role="tabpanel"]')
476 .forEach((p) => p.setAttribute('hidden', true));
477
478 // Show the selected panel
479 grandparent.parentNode
480 .querySelector(`#${target.getAttribute('aria-controls')}`)
481 .removeAttribute('hidden');
482
483
484 lws_tk_selectorMove(target, parent);
485 if (target.id == 'nav-mysql') {
486 reset_table();
487 }
488 }
489 </script>
490
491 <!-- If need a select -->
492 <!-- Change lws_tk! -->
493 <script>
494 if (window.innerWidth <= 1780) {
495 jQuery('#tab_lws_tk').addClass("hidden");
496 jQuery('#tab_lws_tk_select').parent().removeClass("hidden");
497 }
498
499 jQuery(window).on('resize', function() {
500 if (window.innerWidth <= 1780) {
501 jQuery('#tab_lws_tk').addClass("hidden");
502 jQuery('#tab_lws_tk_select').parent().removeClass("hidden");
503 document.getElementById('tab_lws_tk_select').value = document.querySelector(
504 '.tab_nav_lws_tk[aria-selected="true"]').id;
505 } else {
506 jQuery('#tab_lws_tk').removeClass("hidden");
507 jQuery('#tab_lws_tk_select').parent().addClass("hidden");
508 const target = document.getElementById(document.getElementById('tab_lws_tk_select').value);
509 lws_tk_selectorMove(target, target.parentNode);
510 }
511 });
512
513 jQuery('#tab_lws_tk_select').on('change', function() {
514 const target = document.getElementById(this.value);
515 const parent = target.parentNode;
516 const grandparent = parent.parentNode.parentNode;
517
518 // Remove all current selected tabs
519 parent
520 .querySelectorAll('.tab_nav_lws_tk[aria-selected="true"]')
521 .forEach(function(t) {
522 t.setAttribute('aria-selected', false);
523 t.classList.remove("active")
524 });
525
526 // Set this tab as selected
527 target.setAttribute('aria-selected', true);
528 target.classList.add('active');
529
530 // Hide all tab panels
531 grandparent
532 .querySelectorAll('.tab-pane.main-tab-pane[role="tabpanel"]')
533 .forEach((p) => p.setAttribute('hidden', true));
534
535 // Show the selected panel
536 grandparent.parentNode
537 .querySelector(`#${target.getAttribute('aria-controls')}`)
538 .removeAttribute('hidden');
539 });
540 </script>