PluginProbe
Elementor Website Builder – more than just a page builder / 3.22.0-beta1
Elementor Website Builder – more than just a page builder v3.22.0-beta1
4.3.0-beta3 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 All 452 releases
elementor / modules / nested-tabs / widgets / nested-tabs.php

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

1,363 lines 41.2 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 $render_attributes = $this->get_render_attribute_string( $setting_key );
1097 $text_class = $this->get_render_attribute_string( 'tab-title-text' );
1098 $icon_class = $this->get_render_attribute_string( 'tab-icon' );
1099
1100 $icon_html = Icons_Manager::try_get_icon_html( $item_settings['item']['tab_icon'], [ 'aria-hidden' => 'true' ] );
1101 $icon_active_html = $icon_html;
1102
1103 if ( $this->is_active_icon_exist( $item_settings['item'] ) ) {
1104 $icon_active_html = Icons_Manager::try_get_icon_html( $item_settings['item']['tab_icon_active'], [ 'aria-hidden' => 'true' ] );
1105 }
1106
1107 ob_start();
1108 ?>
1109 <button <?php echo $render_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1110 <span <?php echo $icon_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1111 <?php echo $icon_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1112 <?php echo $icon_active_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1113 </span>
1114 <span <?php echo $text_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1115 <?php echo wp_kses_post( $title ); ?>
1116 </span>
1117 </button>
1118 <?php
1119 return ob_get_clean();
1120 }
1121
1122 protected function render_tab_containers_html( $item_settings ): string {
1123 ob_start();
1124 $this->print_child( $item_settings['index'], $item_settings );
1125 return ob_get_clean();
1126 }
1127
1128
1129 /**
1130 * Print the content area.
1131 *
1132 * @param int $index
1133 * @param array $item_settings
1134 */
1135 public function print_child( $index, $item_settings = [] ) {
1136 $children = $this->get_children();
1137 $child_ids = [];
1138
1139 foreach ( $children as $child ) {
1140 $child_ids[] = $child->get_id();
1141 }
1142
1143 // Add data-tab-index attribute to the content area.
1144 $add_attribute_to_container = function ( $should_render, $container ) use ( $item_settings, $child_ids ) {
1145 if ( in_array( $container->get_id(), $child_ids ) ) {
1146 $this->add_attributes_to_container( $container, $item_settings );
1147 }
1148
1149 return $should_render;
1150 };
1151
1152 add_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container, 10, 3 );
1153 if ( isset( $children[ $index ] ) ) {
1154 $children[ $index ]->print_element();
1155 }
1156 remove_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container );
1157 }
1158
1159 protected function add_attributes_to_container( $container, $item_settings ) {
1160 $container->add_render_attribute( '_wrapper', [
1161 'id' => $item_settings['container_id'],
1162 'role' => 'tabpanel',
1163 'aria-labelledby' => $item_settings['tab_id'],
1164 'data-tab-index' => $item_settings['tab_count'],
1165 'style' => '--n-tabs-title-order: ' . $item_settings['tab_count'] . ';',
1166 'class' => 0 === $item_settings['index'] ? 'e-active' : '',
1167 ] );
1168 }
1169
1170 protected function render() {
1171 $settings = $this->get_settings_for_display();
1172 $widget_number = substr( $this->get_id_int(), 0, 3 );
1173
1174 if ( ! empty( $settings['link'] ) ) {
1175 $this->add_link_attributes( 'elementor-tabs', $settings['link'] );
1176 }
1177
1178 $this->add_render_attribute( 'elementor-tabs', [
1179 'class' => 'e-n-tabs',
1180 'data-widget-number' => $widget_number,
1181 'aria-label' => esc_html__( 'Tabs. Open items with Enter or Space, close with Escape and navigate using the Arrow keys.', 'elementor' ),
1182 ] );
1183
1184 $this->add_render_attribute( 'tab-title-text', 'class', 'e-n-tab-title-text' );
1185 $this->add_render_attribute( 'tab-icon', 'class', 'e-n-tab-icon' );
1186 $this->add_render_attribute( 'tab-icon-active', 'class', [ 'e-n-tab-icon' ] );
1187
1188 $tab_titles_html = '';
1189 $tab_containers_html = '';
1190
1191 foreach ( $settings['tabs'] as $index => $item ) {
1192 $tab_count = $index + 1;
1193
1194 $tab_id = empty( $item['element_id'] )
1195 ? 'e-n-tabs-title-' . $widget_number . $tab_count
1196 : $item['element_id'];
1197
1198 $item_settings = [
1199 'index' => $index,
1200 'tab_count' => $tab_count,
1201 'tab_id' => $tab_id,
1202 'container_id' => 'e-n-tab-content-' . $widget_number . $tab_count,
1203 'widget_number' => $widget_number,
1204 'item' => $item,
1205 'settings' => $settings,
1206 ];
1207
1208 $tab_titles_html .= $this->render_tab_titles_html( $item_settings );
1209 $tab_containers_html .= $this->render_tab_containers_html( $item_settings );
1210 }
1211 ?>
1212 <div <?php $this->print_render_attribute_string( 'elementor-tabs' ); ?>>
1213 <div class="e-n-tabs-heading" role="tablist">
1214 <?php echo $tab_titles_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1215 </div>
1216 <div class="e-n-tabs-content">
1217 <?php echo $tab_containers_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1218 </div>
1219 </div>
1220 <?php
1221 }
1222
1223 protected function get_initial_config(): array {
1224 if ( Plugin::$instance->experiments->is_feature_active( 'e_nested_atomic_repeaters' ) ) {
1225 return array_merge( parent::get_initial_config(), [
1226 'support_improved_repeaters' => true,
1227 'target_container' => [ '.e-n-tabs-heading' ],
1228 'node' => 'button',
1229 ] );
1230 }
1231
1232 return parent::get_initial_config();
1233 }
1234
1235 protected function content_template_single_repeater_item() {
1236 ?>
1237 <#
1238 const tabCount = view.collection.length + 1,
1239 elementUid = view.getIDInt().toString().substring( 0, 3 ) + tabCount,
1240 tabIcon = elementor.helpers.renderIcon( view, data.tab_icon, { 'aria-hidden': true }, 'i' , 'object' );
1241
1242 let tabActiveIcon = tabIcon,
1243 tabId = 'e-n-tab-title-' + elementUid;
1244
1245 if ( '' !== data.tab_icon_active.value ) {
1246 tabActiveIcon = elementor.helpers.renderIcon( view, data.tab_icon_active, { 'aria-hidden': true }, 'i' , 'object' );
1247 }
1248
1249 const tabWrapperKey = {
1250 'id': 'e-n-tab-title-' + elementUid,
1251 'class': [ 'e-n-tab-title' ],
1252 'data-tab-index': tabCount,
1253 'role': 'tab',
1254 'aria-selected': 1 === tabCount ? 'true' : 'false',
1255 'tabindex': 1 === tabCount ? '0' : '-1',
1256 'aria-controls': 'e-n-tab-content-' + elementUid,
1257 'style': '--n-tabs-title-order: ' + tabCount + ';',
1258 };
1259
1260 const tabIconKey = {
1261 'class': [ 'e-n-tab-icon' ],
1262 'data-binding-type': 'repeater-item',
1263 'data-binding-repeater-name': 'tabs',
1264 'data-binding-setting': [ data.tab_icon.value, data.tab_icon_active.value ],
1265 'data-binding-index': tabCount,
1266 };
1267
1268 const tabTitleKey = {
1269 'class': [ 'e-n-tab-title-text' ],
1270 'data-binding-type': 'repeater-item',
1271 'data-binding-repeater-name': 'tabs',
1272 'data-binding-setting': [ 'tab_title' ],
1273 'data-binding-index': tabCount,
1274 };
1275
1276 view.addRenderAttribute( 'button-container', tabWrapperKey, null, true );
1277 view.addRenderAttribute( 'tab-title-container', tabTitleKey, null, true );
1278 view.addRenderAttribute( 'tab-icon-key-container', tabIconKey, null, true );
1279 #>
1280
1281 <button {{{ view.getRenderAttributeString( 'button-container' ) }}}>
1282 <span {{{ view.getRenderAttributeString( 'tab-icon-key-container' ) }}}>
1283 {{{ tabIcon.value }}}{{{ tabActiveIcon.value }}}
1284 </span>
1285 <span {{{ view.getRenderAttributeString( 'tab-title-container' ) }}}>{{{ data.tab_title }}}</span>
1286 </button>
1287 <?php
1288 }
1289
1290 protected function content_template() {
1291 ?>
1292 <# const elementUid = view.getIDInt().toString().substr( 0, 3 ); #>
1293 <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' ); ?>">
1294 <# if ( settings['tabs'] ) { #>
1295 <div class="e-n-tabs-heading" role="tablist">
1296 <# _.each( settings['tabs'], function( item, index ) {
1297 const tabCount = index + 1,
1298 tabUid = elementUid + tabCount,
1299 tabWrapperKey = tabUid,
1300 tabTitleKey = 'tab-title-' + tabUid,
1301 tabIconKey = 'tab-icon-' + tabUid,
1302 tabIcon = elementor.helpers.renderIcon( view, item.tab_icon, { 'aria-hidden': true }, 'i' , 'object' ),
1303 hoverAnimationClass = settings['hover_animation'] ? `elementor-animation-${ settings['hover_animation'] }` : '';
1304
1305 let tabActiveIcon = tabIcon,
1306 tabId = 'e-n-tab-title-' + tabUid;
1307
1308 if ( '' !== item.tab_icon_active.value ) {
1309 tabActiveIcon = elementor.helpers.renderIcon( view, item.tab_icon_active, { 'aria-hidden': true }, 'i' , 'object' );
1310 }
1311
1312 if ( '' !== item.element_id ) {
1313 tabId = item.element_id;
1314 }
1315
1316 view.addRenderAttribute( tabWrapperKey, {
1317 'id': tabId,
1318 'class': [ 'e-n-tab-title',hoverAnimationClass ],
1319 'data-tab-index': tabCount,
1320 'role': 'tab',
1321 'aria-selected': 1 === tabCount ? 'true' : 'false',
1322 'tabindex': 1 === tabCount ? '0' : '-1',
1323 'aria-controls': 'e-n-tab-content-' + tabUid,
1324 'style': '--n-tabs-title-order: ' + tabCount + ';',
1325 } );
1326
1327 view.addRenderAttribute( tabTitleKey, {
1328 'class': [ 'e-n-tab-title-text' ],
1329 'data-binding-type': 'repeater-item',
1330 'data-binding-repeater-name': 'tabs',
1331 'data-binding-setting': [ 'tab_title' ],
1332 'data-binding-index': tabCount,
1333 } );
1334
1335 view.addRenderAttribute( tabIconKey, {
1336 'class': [ 'e-n-tab-icon' ],
1337 'data-binding-type': 'repeater-item',
1338 'data-binding-repeater-name': 'tabs',
1339 'data-binding-setting': [ 'tab_icon.value', 'tab_icon_active.value' ],
1340 'data-binding-index': tabCount,
1341 } );
1342 #>
1343 <button {{{ view.getRenderAttributeString( tabWrapperKey ) }}}>
1344 <span {{{ view.getRenderAttributeString( tabIconKey ) }}}>{{{ tabIcon.value }}}{{{ tabActiveIcon.value }}}</span>
1345 <span {{{ view.getRenderAttributeString( tabTitleKey ) }}}>{{{ item.tab_title }}}</span>
1346 </button>
1347 <# } ); #>
1348 </div>
1349 <div class="e-n-tabs-content"></div>
1350 <# } #>
1351 </div>
1352 <?php
1353 }
1354
1355 /**
1356 * @param $item
1357 * @return bool
1358 */
1359 private function is_active_icon_exist( $item ) {
1360 return array_key_exists( 'tab_icon_active', $item ) && ! empty( $item['tab_icon_active'] ) && ! empty( $item['tab_icon_active']['value'] );
1361 }
1362 }
1363