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

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