PluginProbe
Elementor Website Builder – more than just a page builder / 3.21.7
Elementor Website Builder – more than just a page builder v3.21.7
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / nested-tabs / widgets / nested-tabs.php

nested-tabs.php in Elementor Website Builder – more than just a page builder 3.21.7, at modules/nested-tabs/widgets/nested-tabs.php

1,360 lines 41.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\NestedTabs\Widgets;
3
4 use Elementor\Controls_Manager;
5 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
6 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
7 use Elementor\Group_Control_Background;
8 use Elementor\Group_Control_Border;
9 use Elementor\Group_Control_Box_Shadow;
10 use Elementor\Group_Control_Text_Shadow;
11 use Elementor\Group_Control_Text_Stroke;
12 use Elementor\Group_Control_Typography;
13 use Elementor\Icons_Manager;
14 use Elementor\Modules\NestedElements\Base\Widget_Nested_Base;
15 use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
16 use Elementor\Plugin;
17 use Elementor\Repeater;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // Exit if accessed directly
21 }
22
23 class NestedTabs extends Widget_Nested_Base {
24
25 public function get_name() {
26 return 'nested-tabs';
27 }
28
29 public function get_title() {
30 return esc_html__( 'Tabs', 'elementor' );
31 }
32
33 public function get_icon() {
34 return 'eicon-tabs';
35 }
36
37 public function get_keywords() {
38 return [ 'nested', 'tabs', 'accordion', 'toggle' ];
39 }
40
41 protected function tab_content_container( int $index ) {
42 return [
43 'elType' => 'container',
44 'settings' => [
45 '_title' => sprintf( __( 'Tab #%s', 'elementor' ), $index ),
46 'content_width' => 'full',
47 ],
48 ];
49 }
50
51 protected function get_default_children_elements() {
52 return [
53 $this->tab_content_container( 1 ),
54 $this->tab_content_container( 2 ),
55 $this->tab_content_container( 3 ),
56 ];
57 }
58
59 protected function get_default_repeater_title_setting_key() {
60 return 'tab_title';
61 }
62
63 protected function get_default_children_title() {
64 return esc_html__( 'Tab #%d', 'elementor' );
65 }
66
67 protected function get_default_children_placeholder_selector() {
68 return '.e-n-tabs-content';
69 }
70
71 protected function get_html_wrapper_class() {
72 return 'elementor-widget-n-tabs';
73 }
74
75 protected function register_controls() {
76 $start = is_rtl() ? 'right' : 'left';
77 $end = is_rtl() ? 'left' : 'right';
78 $start_logical = is_rtl() ? 'end' : 'start';
79 $end_logical = is_rtl() ? 'start' : 'end';
80 $heading_selector_non_touch_device = '{{WRAPPER}} > .elementor-widget-container > .e-n-tabs[data-touch-mode="false"] > .e-n-tabs-heading';
81 $heading_selector_touch_device = '{{WRAPPER}} > .elementor-widget-container > .e-n-tabs[data-touch-mode="true"] > .e-n-tabs-heading';
82 $heading_selector = '{{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-heading';
83 $content_selector = ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-content ) > .e-con';
84
85 $this->start_controls_section( 'section_tabs', [
86 'label' => esc_html__( 'Tabs', 'elementor' ),
87 ] );
88
89 $repeater = new Repeater();
90
91 $repeater->add_control( 'tab_title', [
92 'label' => esc_html__( 'Title', 'elementor' ),
93 'type' => Controls_Manager::TEXT,
94 'default' => esc_html__( 'Tab Title', 'elementor' ),
95 'placeholder' => esc_html__( 'Tab Title', 'elementor' ),
96 'label_block' => true,
97 'dynamic' => [
98 'active' => true,
99 ],
100 ] );
101
102 $repeater->add_control(
103 'tab_icon',
104 [
105 'label' => esc_html__( 'Icon', 'elementor' ),
106 'type' => Controls_Manager::ICONS,
107 'fa4compatibility' => 'icon',
108 'skin' => 'inline',
109 'label_block' => false,
110 ]
111 );
112
113 $repeater->add_control(
114 'tab_icon_active',
115 [
116 'label' => esc_html__( 'Active Icon', 'elementor' ),
117 'type' => Controls_Manager::ICONS,
118 'fa4compatibility' => 'icon',
119 'skin' => 'inline',
120 'label_block' => false,
121 'condition' => [
122 'tab_icon[value]!' => '',
123 ],
124 ]
125 );
126
127 $repeater->add_control(
128 'element_id',
129 [
130 'label' => esc_html__( 'CSS ID', 'elementor' ),
131 'type' => Controls_Manager::TEXT,
132 'default' => '',
133 'ai' => [
134 'active' => false,
135 ],
136 'dynamic' => [
137 'active' => true,
138 ],
139 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
140 'style_transfer' => false,
141 'classes' => 'elementor-control-direction-ltr',
142 ]
143 );
144
145 $this->add_control( 'tabs', [
146 'label' => esc_html__( 'Tabs Items', 'elementor' ),
147 'type' => Control_Nested_Repeater::CONTROL_TYPE,
148 'fields' => $repeater->get_controls(),
149 'default' => [
150 [
151 'tab_title' => esc_html__( 'Tab #1', 'elementor' ),
152 ],
153 [
154 'tab_title' => esc_html__( 'Tab #2', 'elementor' ),
155 ],
156 [
157 'tab_title' => esc_html__( 'Tab #3', 'elementor' ),
158 ],
159 ],
160 'title_field' => '{{{ tab_title }}}',
161 'button_text' => 'Add Tab',
162 ] );
163
164 $styling_block_start = '--n-tabs-direction: column; --n-tabs-heading-direction: row; --n-tabs-heading-width: initial; --n-tabs-title-flex-basis: content; --n-tabs-title-flex-shrink: 0;';
165 $styling_block_end = '--n-tabs-direction: column-reverse; --n-tabs-heading-direction: row; --n-tabs-heading-width: initial; --n-tabs-title-flex-basis: content; --n-tabs-title-flex-shrink: 0';
166 $styling_inline_end = '--n-tabs-direction: row-reverse; --n-tabs-heading-direction: column; --n-tabs-heading-width: 240px; --n-tabs-title-flex-basis: initial; --n-tabs-title-flex-shrink: initial;';
167 $styling_inline_start = '--n-tabs-direction: row; --n-tabs-heading-direction: column; --n-tabs-heading-width: 240px; --n-tabs-title-flex-basis: initial; --n-tabs-title-flex-shrink: initial;';
168
169 $this->add_responsive_control( 'tabs_direction', [
170 'label' => esc_html__( 'Direction', 'elementor' ),
171 'type' => Controls_Manager::CHOOSE,
172 'options' => [
173 'block-start' => [
174 'title' => esc_html__( 'Above', 'elementor' ),
175 'icon' => 'eicon-v-align-top',
176 ],
177 'block-end' => [
178 'title' => esc_html__( 'Below', 'elementor' ),
179 'icon' => 'eicon-v-align-bottom',
180 ],
181 'inline-end' => [
182 'title' => esc_html__( 'After', 'elementor' ),
183 'icon' => 'eicon-h-align-' . $end,
184 ],
185 'inline-start' => [
186 'title' => esc_html__( 'Before', 'elementor' ),
187 'icon' => 'eicon-h-align-' . $start,
188 ],
189 ],
190 'separator' => 'before',
191 'selectors_dictionary' => [
192 'block-start' => $styling_block_start,
193 'block-end' => $styling_block_end,
194 'inline-end' => $styling_inline_end,
195 'inline-start' => $styling_inline_start,
196 // Styling duplication for BC reasons.
197 'top' => $styling_block_start,
198 'bottom' => $styling_block_end,
199 'end' => $styling_inline_end,
200 'start' => $styling_inline_start,
201 ],
202 'selectors' => [
203 '{{WRAPPER}}' => '{{VALUE}}',
204 ],
205 ] );
206
207 $this->add_responsive_control( 'tabs_justify_horizontal', [
208 'label' => esc_html__( 'Justify', 'elementor' ),
209 'type' => Controls_Manager::CHOOSE,
210 'options' => [
211 'start' => [
212 'title' => esc_html__( 'Start', 'elementor' ),
213 'icon' => "eicon-align-$start_logical-h",
214 ],
215 'center' => [
216 'title' => esc_html__( 'Center', 'elementor' ),
217 'icon' => 'eicon-align-center-h',
218 ],
219 'end' => [
220 'title' => esc_html__( 'End', 'elementor' ),
221 'icon' => "eicon-align-$end_logical-h",
222 ],
223 'stretch' => [
224 'title' => esc_html__( 'Stretch', 'elementor' ),
225 'icon' => 'eicon-align-stretch-h',
226 ],
227 ],
228 'selectors_dictionary' => [
229 'start' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center; --n-tabs-title-flex-grow: 0;',
230 'center' => '--n-tabs-heading-justify-content: center; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center; --n-tabs-title-flex-grow: 0;',
231 'end' => '--n-tabs-heading-justify-content: flex-end; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center; --n-tabs-title-flex-grow: 0;',
232 'stretch' => '--n-tabs-heading-justify-content: initial; --n-tabs-title-width: 100%; --n-tabs-title-height: initial; --n-tabs-title-align-items: center; --n-tabs-title-flex-grow: 1;',
233 ],
234 'selectors' => [
235 '{{WRAPPER}}' => '{{VALUE}}',
236 ],
237 'condition' => [
238 'tabs_direction' => [
239 '',
240 'block-start',
241 'block-end',
242 'top',
243 'bottom',
244 ],
245 ],
246 'frontend_available' => true,
247 ] );
248
249 $this->add_responsive_control( 'tabs_justify_vertical', [
250 'label' => esc_html__( 'Justify', 'elementor' ),
251 'type' => Controls_Manager::CHOOSE,
252 'options' => [
253 'start' => [
254 'title' => esc_html__( 'Start', 'elementor' ),
255 'icon' => 'eicon-align-start-v',
256 ],
257 'center' => [
258 'title' => esc_html__( 'Center', 'elementor' ),
259 'icon' => 'eicon-align-center-v',
260 ],
261 'end' => [
262 'title' => esc_html__( 'End', 'elementor' ),
263 'icon' => 'eicon-align-end-v',
264 ],
265 'stretch' => [
266 'title' => esc_html__( 'Stretch', 'elementor' ),
267 'icon' => 'eicon-align-stretch-v',
268 ],
269 ],
270 'selectors_dictionary' => [
271 'start' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial; --n-tabs-heading-wrap: wrap; --n-tabs-title-flex-basis: content',
272 'center' => '--n-tabs-heading-justify-content: center; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial; --n-tabs-heading-wrap: wrap; --n-tabs-title-flex-basis: content',
273 'end' => '--n-tabs-heading-justify-content: flex-end; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial; --n-tabs-heading-wrap: wrap; --n-tabs-title-flex-basis: content',
274 'stretch' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: 100%; --n-tabs-title-align-items: center; --n-tabs-heading-wrap: nowrap; --n-tabs-title-flex-basis: auto',
275 ],
276 'selectors' => [
277 '{{WRAPPER}}' => '{{VALUE}}',
278 ],
279 'condition' => [
280 'tabs_direction' => [
281 'inline-start',
282 'inline-end',
283 'start',
284 'end',
285 ],
286 ],
287 ] );
288
289 $this->add_responsive_control( 'tabs_width', [
290 'label' => esc_html__( 'Width', 'elementor' ),
291 'type' => Controls_Manager::SLIDER,
292 'range' => [
293 '%' => [
294 'min' => 10,
295 'max' => 50,
296 ],
297 'px' => [
298 'min' => 20,
299 'max' => 600,
300 ],
301 ],
302 'default' => [
303 'unit' => '%',
304 ],
305 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
306 'selectors' => [
307 '{{WRAPPER}}' => '--n-tabs-heading-width: {{SIZE}}{{UNIT}}',
308 ],
309 'condition' => [
310 'tabs_direction' => [
311 'inline-start',
312 'inline-end',
313 'start',
314 'end',
315 ],
316 ],
317 ] );
318
319 $this->add_responsive_control( 'title_alignment', [
320 'label' => esc_html__( 'Align Title', 'elementor' ),
321 'type' => Controls_Manager::CHOOSE,
322 'options' => [
323 'start' => [
324 'title' => esc_html__( 'Start', 'elementor' ),
325 'icon' => 'eicon-text-align-left',
326 ],
327 'center' => [
328 'title' => esc_html__( 'Center', 'elementor' ),
329 'icon' => 'eicon-text-align-center',
330 ],
331 'end' => [
332 'title' => esc_html__( 'End', 'elementor' ),
333 'icon' => 'eicon-text-align-right',
334 ],
335 ],
336 'selectors_dictionary' => [
337 'start' => '--n-tabs-title-justify-content: flex-start; --n-tabs-title-align-items: flex-start; --n-tabs-title-text-align: start;',
338 'center' => '--n-tabs-title-justify-content: center; --n-tabs-title-align-items: center; --n-tabs-title-text-align: center;',
339 'end' => '--n-tabs-title-justify-content: flex-end; --n-tabs-title-align-items: flex-end; --n-tabs-title-text-align: end;',
340 ],
341 'selectors' => [
342 '{{WRAPPER}}' => '{{VALUE}}',
343 ],
344 ] );
345
346 $this->end_controls_section();
347
348 $this->start_controls_section( 'section_tabs_responsive', [
349 'label' => esc_html__( 'Additional Settings', 'elementor' ),
350 ] );
351
352 $this->add_responsive_control(
353 'horizontal_scroll',
354 [
355 'label' => esc_html__( 'Horizontal Scroll', 'elementor' ),
356 'type' => Controls_Manager::SELECT,
357 'description' => esc_html__( 'Note: Scroll tabs if they don’t fit into their parent container.', 'elementor' ),
358 'options' => [
359 'disable' => esc_html__( 'Disable', 'elementor' ),
360 'enable' => esc_html__( 'Enable', 'elementor' ),
361 ],
362 'default' => 'disable',
363 'selectors_dictionary' => [
364 'disable' => '--n-tabs-heading-wrap: wrap; --n-tabs-heading-overflow-x: initial; --n-tabs-title-white-space: initial;',
365 'enable' => '--n-tabs-heading-wrap: nowrap; --n-tabs-heading-overflow-x: scroll; --n-tabs-title-white-space: nowrap;',
366 ],
367 'selectors' => [
368 '{{WRAPPER}}' => '{{VALUE}}',
369 ],
370 'frontend_available' => true,
371 'condition' => [
372 'tabs_direction' => [
373 '',
374 'block-start',
375 'block-end',
376 'top',
377 'bottom',
378 ],
379 ],
380 ]
381 );
382
383 $dropdown_options = [
384 'none' => esc_html__( 'None', 'elementor' ),
385 ];
386 $excluded_breakpoints = [
387 'laptop',
388 'tablet_extra',
389 'widescreen',
390 ];
391
392 foreach ( Plugin::$instance->breakpoints->get_active_breakpoints() as $breakpoint_key => $breakpoint_instance ) {
393 // Exclude the larger breakpoints from the dropdown selector.
394 if ( in_array( $breakpoint_key, $excluded_breakpoints, true ) ) {
395 continue;
396 }
397
398 $dropdown_options[ $breakpoint_key ] = sprintf(
399 /* translators: 1: Breakpoint label, 2: `>` character, 3: Breakpoint value. */
400 esc_html__( '%1$s (%2$s %3$dpx)', 'elementor' ),
401 $breakpoint_instance->get_label(),
402 '>',
403 $breakpoint_instance->get_value()
404 );
405 }
406
407 $this->add_control(
408 'breakpoint_selector',
409 [
410 'label' => esc_html__( 'Breakpoint', 'elementor' ),
411 'type' => Controls_Manager::SELECT,
412 'description' => esc_html__( 'Note: Choose at which breakpoint tabs will automatically switch to a vertical (“accordion”) layout.', 'elementor' ),
413 'options' => $dropdown_options,
414 'default' => 'mobile',
415 'prefix_class' => 'e-n-tabs-',
416 ]
417 );
418
419 $this->end_controls_section();
420
421 $this->start_controls_section( 'section_tabs_style', [
422 'label' => esc_html__( 'Tabs', 'elementor' ),
423 'tab' => Controls_Manager::TAB_STYLE,
424 ] );
425
426 $this->add_responsive_control( 'tabs_title_space_between', [
427 'label' => esc_html__( 'Gap between tabs', 'elementor' ),
428 'type' => Controls_Manager::SLIDER,
429 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
430 'range' => [
431 'px' => [
432 'max' => 400,
433 ],
434 'em' => [
435 'max' => 40,
436 ],
437 'rem' => [
438 'max' => 40,
439 ],
440 ],
441 'selectors' => [
442 '{{WRAPPER}}' => '--n-tabs-title-gap: {{SIZE}}{{UNIT}}',
443 ],
444 ] );
445
446 $this->add_responsive_control( 'tabs_title_spacing', [
447 'label' => esc_html__( 'Distance from content', 'elementor' ),
448 'type' => Controls_Manager::SLIDER,
449 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
450 'range' => [
451 'px' => [
452 'max' => 400,
453 ],
454 'em' => [
455 'max' => 40,
456 ],
457 'rem' => [
458 'max' => 40,
459 ],
460 ],
461 'selectors' => [
462 '{{WRAPPER}}' => '--n-tabs-gap: {{SIZE}}{{UNIT}}',
463 ],
464 ] );
465
466 $this->start_controls_tabs( 'tabs_title_style' );
467
468 $this->start_controls_tab(
469 'tabs_title_normal',
470 [
471 'label' => esc_html__( 'Normal', 'elementor' ),
472 ]
473 );
474
475 $this->add_group_control(
476 Group_Control_Background::get_type(),
477 [
478 'name' => 'tabs_title_background_color',
479 'types' => [ 'classic', 'gradient' ],
480 'exclude' => [ 'image' ],
481 'selector' => '{{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-heading > .e-n-tab-title[aria-selected="false"]:not( :hover )',
482 'fields_options' => [
483 'color' => [
484 'label' => esc_html__( 'Background Color', 'elementor' ),
485 'selectors' => [
486 '{{SELECTOR}}' => 'background: {{VALUE}}',
487 ],
488 ],
489 ],
490 ]
491 );
492
493 $this->add_group_control(
494 Group_Control_Border::get_type(),
495 [
496 'name' => 'tabs_title_border',
497 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"false\"]:not( :hover )",
498 'fields_options' => [
499 'color' => [
500 'label' => esc_html__( 'Border Color', 'elementor' ),
501 ],
502 'width' => [
503 'label' => esc_html__( 'Border Width', 'elementor' ),
504 ],
505 ],
506 ]
507 );
508
509 $this->add_group_control(
510 Group_Control_Box_Shadow::get_type(),
511 [
512 'name' => 'tabs_title_box_shadow',
513 'label' => esc_html__( 'Shadow', 'elementor' ),
514 'separator' => 'after',
515 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"false\"]:not( :hover )",
516 ]
517 );
518
519 $this->end_controls_tab();
520
521 $this->start_controls_tab(
522 'tabs_title_hover',
523 [
524 'label' => esc_html__( 'Hover', 'elementor' ),
525 ]
526 );
527
528 $this->add_group_control(
529 Group_Control_Background::get_type(),
530 [
531 'name' => 'tabs_title_background_color_hover',
532 'types' => [ 'classic', 'gradient' ],
533 'exclude' => [ 'image' ],
534 'selector' => "{$heading_selector_non_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
535 'fields_options' => [
536 'background' => [
537 'default' => 'classic',
538 ],
539 'color' => [
540 'global' => [
541 'default' => Global_Colors::COLOR_ACCENT,
542 ],
543 'label' => esc_html__( 'Background Color', 'elementor' ),
544 'selectors' => [
545 '{{SELECTOR}}' => 'background: {{VALUE}};',
546 ],
547 ],
548 ],
549 ]
550 );
551
552 $this->add_group_control(
553 Group_Control_Border::get_type(),
554 [
555 'name' => 'tabs_title_border_hover',
556 'selector' => "{$heading_selector_non_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
557 'fields_options' => [
558 'color' => [
559 'label' => esc_html__( 'Border Color', 'elementor' ),
560 ],
561 'width' => [
562 'label' => esc_html__( 'Border Width', 'elementor' ),
563 ],
564 ],
565 ]
566 );
567
568 $this->add_group_control(
569 Group_Control_Box_Shadow::get_type(),
570 [
571 'name' => 'tabs_title_box_shadow_hover',
572 'label' => esc_html__( 'Shadow', 'elementor' ),
573 'separator' => 'after',
574 'selector' => "{$heading_selector_non_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
575 ]
576 );
577
578 $this->add_control(
579 'hover_animation',
580 [
581 'label' => esc_html__( 'Hover Animation', 'elementor' ),
582 'type' => Controls_Manager::HOVER_ANIMATION,
583 ]
584 );
585
586 $this->add_control(
587 'tabs_title_transition_duration',
588 [
589 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
590 'type' => Controls_Manager::SLIDER,
591 'selectors' => [
592 '{{WRAPPER}}' => '--n-tabs-title-transition: {{SIZE}}s',
593 ],
594 'range' => [
595 'px' => [
596 'min' => 0,
597 'max' => 3,
598 'step' => 0.1,
599 ],
600 ],
601 ]
602 );
603
604 $this->end_controls_tab();
605
606 $this->start_controls_tab(
607 'tabs_title_active',
608 [
609 'label' => esc_html__( 'Active', 'elementor' ),
610 ]
611 );
612
613 $this->add_group_control(
614 Group_Control_Background::get_type(),
615 [
616 'name' => 'tabs_title_background_color_active',
617 'types' => [ 'classic', 'gradient' ],
618 'exclude' => [ 'image' ],
619 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"true\"], {$heading_selector_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
620 'fields_options' => [
621 'background' => [
622 'default' => 'classic',
623 ],
624 'color' => [
625 'global' => [
626 'default' => Global_Colors::COLOR_ACCENT,
627 ],
628 'label' => esc_html__( 'Background Color', 'elementor' ),
629 'selectors' => [
630 '{{SELECTOR}}' => 'background: {{VALUE}};',
631 ],
632 ],
633 ],
634 ]
635 );
636
637 $this->add_group_control(
638 Group_Control_Border::get_type(),
639 [
640 'name' => 'tabs_title_border_active',
641 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"true\"], {$heading_selector_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
642 'fields_options' => [
643 'color' => [
644 'label' => esc_html__( 'Border Color', 'elementor' ),
645 ],
646 'width' => [
647 'label' => esc_html__( 'Border Width', 'elementor' ),
648 ],
649 ],
650 ]
651 );
652
653 $this->add_group_control(
654 Group_Control_Box_Shadow::get_type(),
655 [
656 'name' => 'tabs_title_box_shadow_active',
657 'label' => esc_html__( 'Shadow', 'elementor' ),
658 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"true\"], {$heading_selector_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
659 ]
660 );
661
662 $this->end_controls_tab();
663
664 $this->end_controls_tabs();
665
666 $this->add_responsive_control(
667 'tabs_title_border_radius',
668 [
669 'label' => esc_html__( 'Border Radius', 'elementor' ),
670 'type' => Controls_Manager::DIMENSIONS,
671 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
672 'separator' => 'before',
673 'selectors' => [
674 '{{WRAPPER}}' => '--n-tabs-title-border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
675 ],
676 ]
677 );
678
679 $this->add_responsive_control(
680 'padding',
681 [
682 'label' => esc_html__( 'Padding', 'elementor' ),
683 'type' => Controls_Manager::DIMENSIONS,
684 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
685 'selectors' => [
686 '{{WRAPPER}}' => '--n-tabs-title-padding-top: {{TOP}}{{UNIT}}; --n-tabs-title-padding-right: {{RIGHT}}{{UNIT}}; --n-tabs-title-padding-bottom: {{BOTTOM}}{{UNIT}}; --n-tabs-title-padding-left: {{LEFT}}{{UNIT}};',
687 ],
688 ]
689 );
690
691 $this->end_controls_section();
692
693 $this->start_controls_section( 'section_title_style', [
694 'label' => esc_html__( 'Titles', 'elementor' ),
695 'tab' => Controls_Manager::TAB_STYLE,
696 ] );
697
698 $this->add_group_control( Group_Control_Typography::get_type(), [
699 'name' => 'title_typography',
700 'global' => [
701 'default' => Global_Typography::TYPOGRAPHY_ACCENT,
702 ],
703 'selector' => "{$heading_selector} > :is( .e-n-tab-title > .e-n-tab-title-text, .e-n-tab-title )",
704 'fields_options' => [
705 'font_size' => [
706 'selectors' => [
707 '{{WRAPPER}}' => '--n-tabs-title-font-size: {{SIZE}}{{UNIT}}',
708 ],
709 ],
710 ],
711 ] );
712
713 $this->start_controls_tabs( 'title_style' );
714
715 $this->start_controls_tab(
716 'title_normal',
717 [
718 'label' => esc_html__( 'Normal', 'elementor' ),
719 ]
720 );
721
722 $this->add_control(
723 'title_text_color',
724 [
725 'label' => esc_html__( 'Color', 'elementor' ),
726 'type' => Controls_Manager::COLOR,
727 'selectors' => [
728 '{{WRAPPER}}' => '--n-tabs-title-color: {{VALUE}}',
729 ],
730 ]
731 );
732
733 $this->add_group_control(
734 Group_Control_Text_Shadow::get_type(),
735 [
736 'name' => 'title_text_shadow',
737 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"false\"]:not( :hover )",
738 'fields_options' => [
739 'text_shadow_type' => [
740 'label' => esc_html__( 'Shadow', 'elementor' ),
741 ],
742 ],
743 ]
744 );
745
746 $this->add_group_control(
747 Group_Control_Text_Stroke::get_type(),
748 [
749 'name' => 'title_text_stroke',
750 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"false\"]:not( :hover ) :is( span, a, i )",
751 'fields_options' => [
752 'text_stroke_type' => [
753 'label' => esc_html__( 'Stroke', 'elementor' ),
754 ],
755 ],
756 ]
757 );
758
759 $this->end_controls_tab();
760
761 $this->start_controls_tab(
762 'title_hover',
763 [
764 'label' => esc_html__( 'Hover', 'elementor' ),
765 ]
766 );
767
768 $this->add_control(
769 'title_text_color_hover',
770 [
771 'label' => esc_html__( 'Color', 'elementor' ),
772 'type' => Controls_Manager::COLOR,
773 'selectors' => [
774 '{{WRAPPER}} [data-touch-mode="false"] .e-n-tab-title[aria-selected="false"]:hover' => '--n-tabs-title-color-hover: {{VALUE}}',
775 ],
776 ]
777 );
778
779 $this->add_group_control(
780 Group_Control_Text_Shadow::get_type(),
781 [
782 'name' => 'title_text_shadow_hover',
783 'selector' => "{$heading_selector_non_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
784 'fields_options' => [
785 'text_shadow_type' => [
786 'label' => esc_html__( 'Shadow', 'elementor' ),
787 ],
788 ],
789
790 ]
791 );
792
793 $this->add_group_control(
794 Group_Control_Text_Stroke::get_type(),
795 [
796 'name' => 'title_text_stroke_hover',
797 'selector' => "{$heading_selector_non_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover :is( span, a, i )",
798 'fields_options' => [
799 'text_stroke_type' => [
800 'label' => esc_html__( 'Stroke', 'elementor' ),
801 ],
802 ],
803 ]
804 );
805
806 $this->end_controls_tab();
807
808 $this->start_controls_tab(
809 'title_active',
810 [
811 'label' => esc_html__( 'Active', 'elementor' ),
812 ]
813 );
814
815 $this->add_control(
816 'title_text_color_active',
817 [
818 'label' => esc_html__( 'Color', 'elementor' ),
819 'type' => Controls_Manager::COLOR,
820 'selectors' => [
821 '{{WRAPPER}}' => '--n-tabs-title-color-active: {{VALUE}}',
822 ],
823 ]
824 );
825
826 $this->add_group_control(
827 Group_Control_Text_Shadow::get_type(),
828 [
829 'name' => 'title_text_shadow_active',
830 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"true\"], {$heading_selector_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover",
831 'fields_options' => [
832 'text_shadow_type' => [
833 'label' => esc_html__( 'Shadow', 'elementor' ),
834 ],
835 ],
836 ]
837 );
838
839 $this->add_group_control(
840 Group_Control_Text_Stroke::get_type(),
841 [
842 'name' => 'title_text_stroke_active',
843 'selector' => "{$heading_selector} > .e-n-tab-title[aria-selected=\"true\"] :is( span, a, i ), {$heading_selector_touch_device} > .e-n-tab-title[aria-selected=\"false\"]:hover :is( span, a, i )",
844 'fields_options' => [
845 'text_stroke_type' => [
846 'label' => esc_html__( 'Stroke', 'elementor' ),
847 ],
848 ],
849 ]
850 );
851
852 $this->end_controls_tab();
853
854 $this->end_controls_tabs();
855
856 $this->end_controls_section();
857
858 $this->start_controls_section( 'icon_section_style', [
859 'label' => esc_html__( 'Icon', 'elementor' ),
860 'tab' => Controls_Manager::TAB_STYLE,
861 ] );
862
863 $styling_block_start = '--n-tabs-title-direction: column; --n-tabs-icon-order: initial; --n-tabs-title-justify-content-toggle: center; --n-tabs-title-align-items-toggle: initial;';
864 $styling_block_end = '--n-tabs-title-direction: column; --n-tabs-icon-order: 1; --n-tabs-title-justify-content-toggle: center; --n-tabs-title-align-items-toggle: initial;';
865 $styling_inline_start = '--n-tabs-title-direction: row; --n-tabs-icon-order: initial; --n-tabs-title-justify-content-toggle: initial; --n-tabs-title-align-items-toggle: center;';
866 $styling_inline_end = '--n-tabs-title-direction: row; --n-tabs-icon-order: 1; --n-tabs-title-justify-content-toggle: initial; --n-tabs-title-align-items-toggle: center;';
867
868 $this->add_responsive_control( 'icon_position', [
869 'label' => esc_html__( 'Position', 'elementor' ),
870 'type' => Controls_Manager::CHOOSE,
871 'options' => [
872 'block-start' => [
873 'title' => esc_html__( 'Above', 'elementor' ),
874 'icon' => 'eicon-v-align-top',
875 ],
876 'inline-end' => [
877 'title' => esc_html__( 'After', 'elementor' ),
878 'icon' => 'eicon-h-align-' . $end,
879 ],
880 'block-end' => [
881 'title' => esc_html__( 'Below', 'elementor' ),
882 'icon' => 'eicon-v-align-bottom',
883 ],
884 'inline-start' => [
885 'title' => esc_html__( 'Before', 'elementor' ),
886 'icon' => 'eicon-h-align-' . $start,
887 ],
888 ],
889 'selectors_dictionary' => [
890 // The toggle variables for 'align items' and 'justify content' have been added to separate the styling of the two 'flex direction' modes.
891 'block-start' => $styling_block_start,
892 'inline-end' => $styling_inline_end,
893 'block-end' => $styling_block_end,
894 'inline-start' => $styling_inline_start,
895 // Styling duplication for BC reasons.
896 'top' => $styling_block_start,
897 'bottom' => $styling_block_end,
898 'start' => $styling_inline_start,
899 'end' => $styling_inline_end,
900 ],
901 'selectors' => [
902 '{{WRAPPER}}' => '{{VALUE}}',
903 ],
904 ] );
905
906 $this->add_responsive_control( 'icon_size', [
907 'label' => esc_html__( 'Size', 'elementor' ),
908 'type' => Controls_Manager::SLIDER,
909 'range' => [
910 'px' => [
911 'max' => 100,
912 ],
913 'em' => [
914 'max' => 10,
915 ],
916 'rem' => [
917 'max' => 10,
918 ],
919 ],
920 'size_units' => [ 'px', 'em', 'rem', 'vw', 'custom' ],
921 'selectors' => [
922 '{{WRAPPER}}' => '--n-tabs-icon-size: {{SIZE}}{{UNIT}}',
923 ],
924 ] );
925
926 $this->add_responsive_control( 'icon_spacing', [
927 'label' => esc_html__( 'Spacing', 'elementor' ),
928 'type' => Controls_Manager::SLIDER,
929 'range' => [
930 'px' => [
931 'max' => 400,
932 ],
933 'vw' => [
934 'max' => 50,
935 'step' => 0.1,
936 ],
937 ],
938 'size_units' => [ 'px', 'em', 'rem', 'vw', 'custom' ],
939 'selectors' => [
940 '{{WRAPPER}}' => '--n-tabs-icon-gap: {{SIZE}}{{UNIT}}',
941 ],
942 ] );
943
944 $this->start_controls_tabs( 'icon_style_states' );
945
946 $this->start_controls_tab(
947 'icon_section_normal',
948 [
949 'label' => esc_html__( 'Normal', 'elementor' ),
950 ]
951 );
952
953 $this->add_control( 'icon_color', [
954 'label' => esc_html__( 'Color', 'elementor' ),
955 'type' => Controls_Manager::COLOR,
956 'selectors' => [
957 '{{WRAPPER}}' => '--n-tabs-icon-color: {{VALUE}};',
958 ],
959 ] );
960
961 $this->end_controls_tab();
962
963 $this->start_controls_tab(
964 'icon_section_hover',
965 [
966 'label' => esc_html__( 'Hover', 'elementor' ),
967 ]
968 );
969
970 $this->add_control( 'icon_color_hover', [
971 'label' => esc_html__( 'Color', 'elementor' ),
972 'type' => Controls_Manager::COLOR,
973 'selectors' => [
974 '{{WRAPPER}} [data-touch-mode="false"] .e-n-tab-title[aria-selected="false"]:hover' => '--n-tabs-icon-color-hover: {{VALUE}};',
975 ],
976 ] );
977
978 $this->end_controls_tab();
979
980 $this->start_controls_tab(
981 'icon_section_active',
982 [
983 'label' => esc_html__( 'Active', 'elementor' ),
984 ]
985 );
986
987 $this->add_control( 'icon_color_active', [
988 'label' => esc_html__( 'Color', 'elementor' ),
989 'type' => Controls_Manager::COLOR,
990 'selectors' => [
991 '{{WRAPPER}}' => '--n-tabs-icon-color-active: {{VALUE}};',
992 ],
993 ] );
994
995 $this->end_controls_tab();
996
997 $this->end_controls_tabs();
998
999 $this->end_controls_section();
1000
1001 $this->start_controls_section( 'section_box_style', [
1002 'label' => esc_html__( 'Content', 'elementor' ),
1003 'tab' => Controls_Manager::TAB_STYLE,
1004 ] );
1005
1006 $this->add_group_control(
1007 Group_Control_Background::get_type(),
1008 [
1009 'name' => 'box_background_color',
1010 'types' => [ 'classic', 'gradient' ],
1011 'exclude' => [ 'image' ],
1012 'selector' => $content_selector,
1013 'fields_options' => [
1014 'color' => [
1015 'label' => esc_html__( 'Background Color', 'elementor' ),
1016 ],
1017 ],
1018 ]
1019 );
1020
1021 $this->add_group_control(
1022 Group_Control_Border::get_type(),
1023 [
1024 'name' => 'box_border',
1025 'selector' => $content_selector,
1026 'fields_options' => [
1027 'color' => [
1028 'label' => esc_html__( 'Border Color', 'elementor' ),
1029 ],
1030 'width' => [
1031 'label' => esc_html__( 'Border Width', 'elementor' ),
1032 ],
1033 ],
1034 ]
1035 );
1036
1037 $this->add_responsive_control(
1038 'box_border_radius',
1039 [
1040 'label' => esc_html__( 'Border Radius', 'elementor' ),
1041 'type' => Controls_Manager::DIMENSIONS,
1042 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
1043 'selectors' => [
1044 $content_selector => '--border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1045 ],
1046 ]
1047 );
1048
1049 $this->add_group_control(
1050 Group_Control_Box_Shadow::get_type(),
1051 [
1052 'name' => 'box_shadow_box_shadow',
1053 'selector' => $content_selector,
1054 'condition' => [
1055 'box_height!' => 'height',
1056 ],
1057 ]
1058 );
1059
1060 $this->add_responsive_control(
1061 'box_padding',
1062 [
1063 'label' => esc_html__( 'Padding', 'elementor' ),
1064 'type' => Controls_Manager::DIMENSIONS,
1065 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1066 'selectors' => [
1067 $content_selector => '--padding-top: {{TOP}}{{UNIT}}; --padding-right: {{RIGHT}}{{UNIT}}; --padding-bottom: {{BOTTOM}}{{UNIT}}; --padding-left: {{LEFT}}{{UNIT}};',
1068 ],
1069 ]
1070 );
1071
1072 $this->end_controls_section();
1073 }
1074
1075 protected function render_tab_titles_html( $item_settings ): string {
1076 $setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $item_settings['index'] );
1077 $title = $item_settings['item']['tab_title'];
1078 $css_classes = [ 'e-n-tab-title' ];
1079
1080 if ( $item_settings['settings']['hover_animation'] ) {
1081 $css_classes[] = 'elementor-animation-' . $item_settings['settings']['hover_animation'];
1082 }
1083
1084 $this->add_render_attribute( $setting_key, [
1085 'id' => $item_settings['tab_id'],
1086 'class' => $css_classes,
1087 'aria-selected' => 1 === $item_settings['tab_count'] ? 'true' : 'false',
1088 'data-tab-index' => $item_settings['tab_count'],
1089 'role' => 'tab',
1090 'tabindex' => 1 === $item_settings['tab_count'] ? '0' : '-1',
1091 'aria-controls' => $item_settings['container_id'],
1092 'style' => '--n-tabs-title-order: ' . $item_settings['tab_count'] . ';',
1093 ] );
1094
1095 $render_attributes = $this->get_render_attribute_string( $setting_key );
1096 $text_class = $this->get_render_attribute_string( 'tab-title-text' );
1097 $icon_class = $this->get_render_attribute_string( 'tab-icon' );
1098
1099 $icon_html = Icons_Manager::try_get_icon_html( $item_settings['item']['tab_icon'], [ 'aria-hidden' => 'true' ] );
1100 $icon_active_html = $icon_html;
1101
1102 if ( $this->is_active_icon_exist( $item_settings['item'] ) ) {
1103 $icon_active_html = Icons_Manager::try_get_icon_html( $item_settings['item']['tab_icon_active'], [ 'aria-hidden' => 'true' ] );
1104 }
1105
1106 ob_start();
1107 ?>
1108 <button <?php echo $render_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1109 <span <?php echo $icon_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1110 <?php echo $icon_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1111 <?php echo $icon_active_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1112 </span>
1113 <span <?php echo $text_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1114 <?php echo wp_kses_post( $title ); ?>
1115 </span>
1116 </button>
1117 <?php
1118 return ob_get_clean();
1119 }
1120
1121 protected function render_tab_containers_html( $item_settings ): string {
1122 ob_start();
1123 $this->print_child( $item_settings['index'], $item_settings );
1124 return ob_get_clean();
1125 }
1126
1127
1128 /**
1129 * Print the content area.
1130 *
1131 * @param int $index
1132 * @param array $item_settings
1133 */
1134 public function print_child( $index, $item_settings = [] ) {
1135 $children = $this->get_children();
1136 $child_ids = [];
1137
1138 foreach ( $children as $child ) {
1139 $child_ids[] = $child->get_id();
1140 }
1141
1142 // Add data-tab-index attribute to the content area.
1143 $add_attribute_to_container = function ( $should_render, $container ) use ( $item_settings, $child_ids ) {
1144 if ( in_array( $container->get_id(), $child_ids ) ) {
1145 $this->add_attributes_to_container( $container, $item_settings );
1146 }
1147
1148 return $should_render;
1149 };
1150
1151 add_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container, 10, 3 );
1152 $children[ $index ]->print_element();
1153 remove_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container );
1154 }
1155
1156 protected function add_attributes_to_container( $container, $item_settings ) {
1157 $container->add_render_attribute( '_wrapper', [
1158 'id' => $item_settings['container_id'],
1159 'role' => 'tabpanel',
1160 'aria-labelledby' => $item_settings['tab_id'],
1161 'data-tab-index' => $item_settings['tab_count'],
1162 'style' => '--n-tabs-title-order: ' . $item_settings['tab_count'] . ';',
1163 'class' => 0 === $item_settings['index'] ? 'e-active' : '',
1164 ] );
1165 }
1166
1167 protected function render() {
1168 $settings = $this->get_settings_for_display();
1169 $widget_number = substr( $this->get_id_int(), 0, 3 );
1170
1171 if ( ! empty( $settings['link'] ) ) {
1172 $this->add_link_attributes( 'elementor-tabs', $settings['link'] );
1173 }
1174
1175 $this->add_render_attribute( 'elementor-tabs', [
1176 'class' => 'e-n-tabs',
1177 'data-widget-number' => $widget_number,
1178 'aria-label' => esc_html__( 'Tabs. Open items with Enter or Space, close with Escape and navigate using the Arrow keys.', 'elementor' ),
1179 ] );
1180
1181 $this->add_render_attribute( 'tab-title-text', 'class', 'e-n-tab-title-text' );
1182 $this->add_render_attribute( 'tab-icon', 'class', 'e-n-tab-icon' );
1183 $this->add_render_attribute( 'tab-icon-active', 'class', [ 'e-n-tab-icon' ] );
1184
1185 $tab_titles_html = '';
1186 $tab_containers_html = '';
1187
1188 foreach ( $settings['tabs'] as $index => $item ) {
1189 $tab_count = $index + 1;
1190
1191 $tab_id = empty( $item['element_id'] )
1192 ? 'e-n-tabs-title-' . $widget_number . $tab_count
1193 : $item['element_id'];
1194
1195 $item_settings = [
1196 'index' => $index,
1197 'tab_count' => $tab_count,
1198 'tab_id' => $tab_id,
1199 'container_id' => 'e-n-tab-content-' . $widget_number . $tab_count,
1200 'widget_number' => $widget_number,
1201 'item' => $item,
1202 'settings' => $settings,
1203 ];
1204
1205 $tab_titles_html .= $this->render_tab_titles_html( $item_settings );
1206 $tab_containers_html .= $this->render_tab_containers_html( $item_settings );
1207 }
1208 ?>
1209 <div <?php $this->print_render_attribute_string( 'elementor-tabs' ); ?>>
1210 <div class="e-n-tabs-heading" role="tablist">
1211 <?php echo $tab_titles_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1212 </div>
1213 <div class="e-n-tabs-content">
1214 <?php echo $tab_containers_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1215 </div>
1216 </div>
1217 <?php
1218 }
1219
1220 protected function get_initial_config(): array {
1221 if ( Plugin::$instance->experiments->is_feature_active( 'e_nested_atomic_repeaters' ) ) {
1222 return array_merge( parent::get_initial_config(), [
1223 'support_improved_repeaters' => true,
1224 'target_container' => [ '.e-n-tabs-heading' ],
1225 'node' => 'button',
1226 ] );
1227 }
1228
1229 return parent::get_initial_config();
1230 }
1231
1232 protected function content_template_single_repeater_item() {
1233 ?>
1234 <#
1235 const tabCount = view.collection.length + 1,
1236 elementUid = view.getIDInt().toString().substring( 0, 3 ) + tabCount,
1237 tabIcon = elementor.helpers.renderIcon( view, data.tab_icon, { 'aria-hidden': true }, 'i' , 'object' );
1238
1239 let tabActiveIcon = tabIcon,
1240 tabId = 'e-n-tab-title-' + elementUid;
1241
1242 if ( '' !== data.tab_icon_active.value ) {
1243 tabActiveIcon = elementor.helpers.renderIcon( view, data.tab_icon_active, { 'aria-hidden': true }, 'i' , 'object' );
1244 }
1245
1246 const tabWrapperKey = {
1247 'id': 'e-n-tab-title-' + elementUid,
1248 'class': [ 'e-n-tab-title' ],
1249 'data-tab-index': tabCount,
1250 'role': 'tab',
1251 'aria-selected': 1 === tabCount ? 'true' : 'false',
1252 'tabindex': 1 === tabCount ? '0' : '-1',
1253 'aria-controls': 'e-n-tab-content-' + elementUid,
1254 'style': '--n-tabs-title-order: ' + tabCount + ';',
1255 };
1256
1257 const tabIconKey = {
1258 'class': [ 'e-n-tab-icon' ],
1259 'data-binding-type': 'repeater-item',
1260 'data-binding-repeater-name': 'tabs',
1261 'data-binding-setting': [ data.tab_icon.value, data.tab_icon_active.value ],
1262 'data-binding-index': tabCount,
1263 };
1264
1265 const tabTitleKey = {
1266 'class': [ 'e-n-tab-title-text' ],
1267 'data-binding-type': 'repeater-item',
1268 'data-binding-repeater-name': 'tabs',
1269 'data-binding-setting': [ 'tab_title' ],
1270 'data-binding-index': tabCount,
1271 };
1272
1273 view.addRenderAttribute( 'button-container', tabWrapperKey, null, true );
1274 view.addRenderAttribute( 'tab-title-container', tabTitleKey, null, true );
1275 view.addRenderAttribute( 'tab-icon-key-container', tabIconKey, null, true );
1276 #>
1277
1278 <button {{{ view.getRenderAttributeString( 'button-container' ) }}}>
1279 <span {{{ view.getRenderAttributeString( 'tab-icon-key-container' ) }}}>
1280 {{{ tabIcon.value }}}{{{ tabActiveIcon.value }}}
1281 </span>
1282 <span {{{ view.getRenderAttributeString( 'tab-title-container' ) }}}>{{{ data.tab_title }}}</span>
1283 </button>
1284 <?php
1285 }
1286
1287 protected function content_template() {
1288 ?>
1289 <# const elementUid = view.getIDInt().toString().substr( 0, 3 ); #>
1290 <div class="e-n-tabs" data-widget-number="{{ elementUid }}" aria-label="<?php echo esc_html__( 'Tabs. Open items with Enter or Space, close with Escape and navigate using the Arrow keys.', 'elementor' ); ?>">
1291 <# if ( settings['tabs'] ) { #>
1292 <div class="e-n-tabs-heading" role="tablist">
1293 <# _.each( settings['tabs'], function( item, index ) {
1294 const tabCount = index + 1,
1295 tabUid = elementUid + tabCount,
1296 tabWrapperKey = tabUid,
1297 tabTitleKey = 'tab-title-' + tabUid,
1298 tabIconKey = 'tab-icon-' + tabUid,
1299 tabIcon = elementor.helpers.renderIcon( view, item.tab_icon, { 'aria-hidden': true }, 'i' , 'object' ),
1300 hoverAnimationClass = settings['hover_animation'] ? `elementor-animation-${ settings['hover_animation'] }` : '';
1301
1302 let tabActiveIcon = tabIcon,
1303 tabId = 'e-n-tab-title-' + tabUid;
1304
1305 if ( '' !== item.tab_icon_active.value ) {
1306 tabActiveIcon = elementor.helpers.renderIcon( view, item.tab_icon_active, { 'aria-hidden': true }, 'i' , 'object' );
1307 }
1308
1309 if ( '' !== item.element_id ) {
1310 tabId = item.element_id;
1311 }
1312
1313 view.addRenderAttribute( tabWrapperKey, {
1314 'id': tabId,
1315 'class': [ 'e-n-tab-title',hoverAnimationClass ],
1316 'data-tab-index': tabCount,
1317 'role': 'tab',
1318 'aria-selected': 1 === tabCount ? 'true' : 'false',
1319 'tabindex': 1 === tabCount ? '0' : '-1',
1320 'aria-controls': 'e-n-tab-content-' + tabUid,
1321 'style': '--n-tabs-title-order: ' + tabCount + ';',
1322 } );
1323
1324 view.addRenderAttribute( tabTitleKey, {
1325 'class': [ 'e-n-tab-title-text' ],
1326 'data-binding-type': 'repeater-item',
1327 'data-binding-repeater-name': 'tabs',
1328 'data-binding-setting': [ 'tab_title' ],
1329 'data-binding-index': tabCount,
1330 } );
1331
1332 view.addRenderAttribute( tabIconKey, {
1333 'class': [ 'e-n-tab-icon' ],
1334 'data-binding-type': 'repeater-item',
1335 'data-binding-repeater-name': 'tabs',
1336 'data-binding-setting': [ 'tab_icon.value', 'tab_icon_active.value' ],
1337 'data-binding-index': tabCount,
1338 } );
1339 #>
1340 <button {{{ view.getRenderAttributeString( tabWrapperKey ) }}}>
1341 <span {{{ view.getRenderAttributeString( tabIconKey ) }}}>{{{ tabIcon.value }}}{{{ tabActiveIcon.value }}}</span>
1342 <span {{{ view.getRenderAttributeString( tabTitleKey ) }}}>{{{ item.tab_title }}}</span>
1343 </button>
1344 <# } ); #>
1345 </div>
1346 <div class="e-n-tabs-content"></div>
1347 <# } #>
1348 </div>
1349 <?php
1350 }
1351
1352 /**
1353 * @param $item
1354 * @return bool
1355 */
1356 private function is_active_icon_exist( $item ) {
1357 return array_key_exists( 'tab_icon_active', $item ) && ! empty( $item['tab_icon_active'] ) && ! empty( $item['tab_icon_active']['value'] );
1358 }
1359 }
1360