PluginProbe
Elementor Website Builder – more than just a page builder / 3.26.0-dev5
Elementor Website Builder – more than just a page builder v3.26.0-dev5
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.26.0-dev5, at modules/nested-tabs/widgets/nested-tabs.php

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