PluginProbe
Elementor Website Builder – more than just a page builder / 3.19.0-beta5
Elementor Website Builder – more than just a page builder v3.19.0-beta5
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 / includes / widgets / common.php

common.php in Elementor Website Builder – more than just a page builder 3.19.0-beta5, at includes/widgets/common.php

1,174 lines 28.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly.
8 }
9
10 /**
11 * Elementor common widget.
12 *
13 * Elementor base widget that gives you all the advanced options of the basic
14 * widget.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Common extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve common widget name.
24 *
25 * @since 1.0.0
26 * @access public
27 *
28 * @return string Widget name.
29 */
30 public function get_name() {
31 return 'common';
32 }
33
34 /**
35 * Show in panel.
36 *
37 * Whether to show the common widget in the panel or not.
38 *
39 * @since 1.0.0
40 * @access public
41 *
42 * @return bool Whether to show the widget in the panel.
43 */
44 public function show_in_panel() {
45 return false;
46 }
47
48 /**
49 * Get Responsive Device Args
50 *
51 * Receives an array of device args, and duplicates it for each active breakpoint.
52 * Returns an array of device args.
53 *
54 * @since 3.4.7
55 * @deprecated 3.7.0 Not needed anymore because responsive conditioning in the Editor was fixed in v3.7.0.
56 * @access protected
57 *
58 * @param array $args arguments to duplicate per breakpoint
59 * @param array $devices_to_exclude
60 *
61 * @return array responsive device args
62 */
63 protected function get_responsive_device_args( array $args, array $devices_to_exclude = [] ) {
64 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.7.0' );
65
66 $device_args = [];
67 $breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();
68
69 foreach ( $breakpoints as $breakpoint_key => $breakpoint ) {
70 // If the device is not excluded, add it to the device args array.
71 if ( ! in_array( $breakpoint_key, $devices_to_exclude, true ) ) {
72 $parsed_device_args = $this->parse_device_args_placeholders( $args, $breakpoint_key );
73
74 $device_args[ $breakpoint_key ] = $parsed_device_args;
75 }
76 }
77
78 return $device_args;
79 }
80
81 /**
82 * Parse Device Args Placeholders
83 *
84 * Receives an array of args. Iterates over the args, and replaces the {{DEVICE}} placeholder, if exists, with the
85 * passed breakpoint key.
86 *
87 * @since 3.4.7
88 * @access private
89 *
90 * @param array $args
91 * @param string $breakpoint_key
92 * @return array parsed device args
93 */
94 private function parse_device_args_placeholders( array $args, $breakpoint_key ) {
95 $parsed_args = [];
96
97 foreach ( $args as $arg_key => $arg_value ) {
98 $arg_key = str_replace( '{{DEVICE}}', $breakpoint_key, $arg_key );
99
100 if ( is_array( $arg_value ) ) {
101 $arg_value = $this->parse_device_args_placeholders( $arg_value, $breakpoint_key );
102 }
103
104 $parsed_args[ $arg_key ] = $arg_value;
105 }
106
107 return $parsed_args;
108 }
109
110 /**
111 * @param $shape String Shape name.
112 *
113 * @return string The shape path in the assets folder.
114 */
115 private function get_shape_url( $shape ) {
116 return ELEMENTOR_ASSETS_URL . 'mask-shapes/' . $shape . '.svg';
117 }
118
119 /**
120 * Return a translated user-friendly list of the available masking shapes.
121 *
122 * @param bool $add_custom Determine if the output should contain `Custom` options.
123 *
124 * @return array Array of shapes with their URL as key.
125 */
126 private function get_shapes( $add_custom = true ) {
127 $shapes = [
128 'circle' => esc_html__( 'Circle', 'elementor' ),
129 'flower' => esc_html__( 'Flower', 'elementor' ),
130 'sketch' => esc_html__( 'Sketch', 'elementor' ),
131 'triangle' => esc_html__( 'Triangle', 'elementor' ),
132 'blob' => esc_html__( 'Blob', 'elementor' ),
133 'hexagon' => esc_html__( 'Hexagon', 'elementor' ),
134 ];
135
136 if ( $add_custom ) {
137 $shapes['custom'] = esc_html__( 'Custom', 'elementor' );
138 }
139
140 return $shapes;
141 }
142
143 /**
144 * Gets a string of CSS rules to apply, and returns an array of selectors with those rules.
145 * This function has been created in order to deal with masking for image widget.
146 * For most of the widgets the mask is being applied to the wrapper itself, but in the case of an image widget,
147 * the `img` tag should be masked directly. So instead of writing a lot of selectors every time,
148 * this function builds both of those selectors easily.
149 *
150 * @param $rules string The CSS rules to apply.
151 *
152 * @return array Selectors with the rules applied.
153 */
154 private function get_mask_selectors( $rules ) {
155 $mask_selectors = [
156 'default' => '{{WRAPPER}}:not( .elementor-widget-image ) .elementor-widget-container',
157 'image' => '{{WRAPPER}}.elementor-widget-image .elementor-widget-container img',
158 ];
159
160 return [
161 $mask_selectors['default'] => $rules,
162 $mask_selectors['image'] => $rules,
163 ];
164 }
165
166 /**
167 * Register the Layout section.
168 *
169 * @return void
170 */
171 private function register_layout_section() {
172 $this->start_controls_section(
173 '_section_style',
174 [
175 'label' => esc_html__( 'Layout', 'elementor' ),
176 'tab' => Controls_Manager::TAB_ADVANCED,
177 ]
178 );
179
180 // Element Name for the Navigator
181 $this->add_control(
182 '_title',
183 [
184 'label' => esc_html__( 'Title', 'elementor' ),
185 'type' => Controls_Manager::HIDDEN,
186 'render_type' => 'none',
187 ]
188 );
189
190 $this->add_responsive_control(
191 '_margin',
192 [
193 'label' => esc_html__( 'Margin', 'elementor' ),
194 'type' => Controls_Manager::DIMENSIONS,
195 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
196 'selectors' => [
197 '{{WRAPPER}} > .elementor-widget-container' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
198 ],
199 ]
200 );
201
202 $this->add_responsive_control(
203 '_padding',
204 [
205 'label' => esc_html__( 'Padding', 'elementor' ),
206 'type' => Controls_Manager::DIMENSIONS,
207 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
208 'selectors' => [
209 '{{WRAPPER}} > .elementor-widget-container' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
210 ],
211 ]
212 );
213
214 $experiments_manager = Plugin::$instance->experiments;
215 $is_container_active = $experiments_manager->is_feature_active( 'container' );
216
217 $this->add_responsive_control(
218 '_element_width',
219 [
220 'label' => esc_html__( 'Width', 'elementor' ),
221 'type' => Controls_Manager::SELECT,
222 'default' => '',
223 'options' => [
224 '' => esc_html__( 'Default', 'elementor' ),
225 'inherit' => esc_html__( 'Full Width', 'elementor' ) . ' (100%)',
226 'auto' => esc_html__( 'Inline', 'elementor' ) . ' (auto)',
227 'initial' => esc_html__( 'Custom', 'elementor' ),
228 ],
229 'selectors_dictionary' => [
230 'inherit' => '100%',
231 ],
232 'prefix_class' => 'elementor-widget%s__width-',
233 'selectors' => [
234 '{{WRAPPER}}' => 'width: {{VALUE}}; max-width: {{VALUE}}',
235 ],
236 ]
237 );
238
239 $this->add_responsive_control(
240 '_element_custom_width',
241 [
242 'label' => esc_html__( 'Custom Width', 'elementor' ),
243 'type' => Controls_Manager::SLIDER,
244 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
245 'default' => [
246 'unit' => '%',
247 ],
248 'range' => [
249 'px' => [
250 'max' => 1000,
251 ],
252 ],
253 'selectors' => [
254 '{{WRAPPER}}' => '--container-widget-width: {{SIZE}}{{UNIT}}; --container-widget-flex-grow: 0; width: var( --container-widget-width, {{SIZE}}{{UNIT}} ); max-width: {{SIZE}}{{UNIT}}',
255 ],
256 'condition' => [ '_element_width' => 'initial' ],
257 ]
258 );
259
260 // Register Flex controls only if the Container experiment is active.
261 if ( $is_container_active ) {
262 $this->add_group_control(
263 Group_Control_Flex_Item::get_type(),
264 [
265 'name' => '_flex',
266 // Hack to increase specificity and make sure that the current widget overrides the
267 // parent flex settings.
268 'selector' => '{{WRAPPER}}.elementor-element',
269 'include' => [
270 'align_self',
271 'order',
272 'order_custom',
273 'size',
274 'grow',
275 'shrink',
276 ],
277 'fields_options' => [
278 'align_self' => [
279 'separator' => 'before',
280 ],
281 ],
282 ]
283 );
284 }
285
286 $vertical_align_conditions = [
287 '_element_width!' => '',
288 '_position' => '',
289 ];
290
291 if ( $is_container_active ) {
292 $vertical_align_conditions['_element_vertical_align!'] = ''; // TODO: For BC.
293 }
294
295 // TODO: For BC - Remove in the future.
296 $this->add_responsive_control(
297 '_element_vertical_align',
298 [
299 'label' => esc_html__( 'Vertical Align', 'elementor' ),
300 'type' => Controls_Manager::CHOOSE,
301 'options' => [
302 'flex-start' => [
303 'title' => esc_html__( 'Start', 'elementor' ),
304 'icon' => 'eicon-v-align-top',
305 ],
306 'center' => [
307 'title' => esc_html__( 'Center', 'elementor' ),
308 'icon' => 'eicon-v-align-middle',
309 ],
310 'flex-end' => [
311 'title' => esc_html__( 'End', 'elementor' ),
312 'icon' => 'eicon-v-align-bottom',
313 ],
314 ],
315 'condition' => $vertical_align_conditions,
316 'selectors' => [
317 '{{WRAPPER}}' => 'align-self: {{VALUE}}',
318 ],
319 ]
320 );
321
322 $this->add_control(
323 '_position_description',
324 [
325 'raw' => '<strong>' . esc_html__( 'Please note!', 'elementor' ) . '</strong> ' . esc_html__( 'Custom positioning is not considered best practice for responsive web design and should not be used too frequently.', 'elementor' ),
326 'type' => Controls_Manager::RAW_HTML,
327 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning',
328 'render_type' => 'ui',
329 'condition' => [
330 '_position!' => '',
331 ],
332 ]
333 );
334
335 $this->add_control(
336 '_position',
337 [
338 'label' => esc_html__( 'Position', 'elementor' ),
339 'type' => Controls_Manager::SELECT,
340 'default' => '',
341 'options' => [
342 '' => esc_html__( 'Default', 'elementor' ),
343 'absolute' => esc_html__( 'Absolute', 'elementor' ),
344 'fixed' => esc_html__( 'Fixed', 'elementor' ),
345 ],
346 'prefix_class' => 'elementor-',
347 'frontend_available' => true,
348 'separator' => 'before',
349 ]
350 );
351
352 $start = is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
353 $end = ! is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
354
355 $this->add_control(
356 '_offset_orientation_h',
357 [
358 'label' => esc_html__( 'Horizontal Orientation', 'elementor' ),
359 'type' => Controls_Manager::CHOOSE,
360 'toggle' => false,
361 'default' => 'start',
362 'options' => [
363 'start' => [
364 'title' => $start,
365 'icon' => 'eicon-h-align-left',
366 ],
367 'end' => [
368 'title' => $end,
369 'icon' => 'eicon-h-align-right',
370 ],
371 ],
372 'classes' => 'elementor-control-start-end',
373 'render_type' => 'ui',
374 'condition' => [
375 '_position!' => '',
376 ],
377 ]
378 );
379
380 $this->add_responsive_control(
381 '_offset_x',
382 [
383 'label' => esc_html__( 'Offset', 'elementor' ),
384 'type' => Controls_Manager::SLIDER,
385 'range' => [
386 'px' => [
387 'min' => -1000,
388 'max' => 1000,
389 ],
390 '%' => [
391 'min' => -200,
392 'max' => 200,
393 ],
394 'vw' => [
395 'min' => -200,
396 'max' => 200,
397 ],
398 'vh' => [
399 'min' => -200,
400 'max' => 200,
401 ],
402 ],
403 'default' => [
404 'size' => 0,
405 ],
406 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
407 'selectors' => [
408 'body:not(.rtl) {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
409 'body.rtl {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
410 ],
411 'condition' => [
412 '_offset_orientation_h!' => 'end',
413 '_position!' => '',
414 ],
415 ]
416 );
417
418 $this->add_responsive_control(
419 '_offset_x_end',
420 [
421 'label' => esc_html__( 'Offset', 'elementor' ),
422 'type' => Controls_Manager::SLIDER,
423 'range' => [
424 'px' => [
425 'min' => -1000,
426 'max' => 1000,
427 ],
428 '%' => [
429 'min' => -200,
430 'max' => 200,
431 ],
432 'vw' => [
433 'min' => -200,
434 'max' => 200,
435 ],
436 'vh' => [
437 'min' => -200,
438 'max' => 200,
439 ],
440 ],
441 'default' => [
442 'size' => 0,
443 ],
444 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
445 'selectors' => [
446 'body:not(.rtl) {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
447 'body.rtl {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
448 ],
449 'condition' => [
450 '_offset_orientation_h' => 'end',
451 '_position!' => '',
452 ],
453 ]
454 );
455
456 $this->add_control(
457 '_offset_orientation_v',
458 [
459 'label' => esc_html__( 'Vertical Orientation', 'elementor' ),
460 'type' => Controls_Manager::CHOOSE,
461 'toggle' => false,
462 'default' => 'start',
463 'options' => [
464 'start' => [
465 'title' => esc_html__( 'Top', 'elementor' ),
466 'icon' => 'eicon-v-align-top',
467 ],
468 'end' => [
469 'title' => esc_html__( 'Bottom', 'elementor' ),
470 'icon' => 'eicon-v-align-bottom',
471 ],
472 ],
473 'render_type' => 'ui',
474 'condition' => [
475 '_position!' => '',
476 ],
477 ]
478 );
479
480 $this->add_responsive_control(
481 '_offset_y',
482 [
483 'label' => esc_html__( 'Offset', 'elementor' ),
484 'type' => Controls_Manager::SLIDER,
485 'range' => [
486 'px' => [
487 'min' => -1000,
488 'max' => 1000,
489 ],
490 '%' => [
491 'min' => -200,
492 'max' => 200,
493 ],
494 'vh' => [
495 'min' => -200,
496 'max' => 200,
497 ],
498 'vw' => [
499 'min' => -200,
500 'max' => 200,
501 ],
502 ],
503 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
504 'default' => [
505 'size' => 0,
506 ],
507 'selectors' => [
508 '{{WRAPPER}}' => 'top: {{SIZE}}{{UNIT}}',
509 ],
510 'condition' => [
511 '_offset_orientation_v!' => 'end',
512 '_position!' => '',
513 ],
514 ]
515 );
516
517 $this->add_responsive_control(
518 '_offset_y_end',
519 [
520 'label' => esc_html__( 'Offset', 'elementor' ),
521 'type' => Controls_Manager::SLIDER,
522 'range' => [
523 'px' => [
524 'min' => -1000,
525 'max' => 1000,
526 ],
527 '%' => [
528 'min' => -200,
529 'max' => 200,
530 ],
531 'vh' => [
532 'min' => -200,
533 'max' => 200,
534 ],
535 'vw' => [
536 'min' => -200,
537 'max' => 200,
538 ],
539 ],
540 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
541 'default' => [
542 'size' => 0,
543 ],
544 'selectors' => [
545 '{{WRAPPER}}' => 'bottom: {{SIZE}}{{UNIT}}',
546 ],
547 'condition' => [
548 '_offset_orientation_v' => 'end',
549 '_position!' => '',
550 ],
551 ]
552 );
553
554 $this->add_responsive_control(
555 '_z_index',
556 [
557 'label' => esc_html__( 'Z-Index', 'elementor' ),
558 'type' => Controls_Manager::NUMBER,
559 'selectors' => [
560 '{{WRAPPER}}' => 'z-index: {{VALUE}};',
561 ],
562 ]
563 );
564
565 $this->add_control(
566 '_element_id',
567 [
568 'label' => esc_html__( 'CSS ID', 'elementor' ),
569 'type' => Controls_Manager::TEXT,
570 'dynamic' => [
571 'active' => true,
572 ],
573 'ai' => [
574 'active' => false,
575 ],
576 'default' => '',
577 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
578 'style_transfer' => false,
579 'classes' => 'elementor-control-direction-ltr',
580 ]
581 );
582
583 $this->add_control(
584 '_css_classes',
585 [
586 'label' => esc_html__( 'CSS Classes', 'elementor' ),
587 'type' => Controls_Manager::TEXT,
588 'ai' => [
589 'active' => false,
590 ],
591 'dynamic' => [
592 'active' => true,
593 ],
594 'prefix_class' => '',
595 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
596 'classes' => 'elementor-control-direction-ltr',
597 ]
598 );
599
600 Plugin::$instance->controls_manager->add_display_conditions_controls( $this );
601
602 $this->end_controls_section();
603 }
604
605 /**
606 * Register the Motion Effects section.
607 *
608 * @return void
609 */
610 private function register_effects_section() {
611 $this->start_controls_section(
612 'section_effects',
613 [
614 'label' => esc_html__( 'Motion Effects', 'elementor' ),
615 'tab' => Controls_Manager::TAB_ADVANCED,
616 ]
617 );
618
619 $this->add_responsive_control(
620 '_animation',
621 [
622 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
623 'type' => Controls_Manager::ANIMATION,
624 'frontend_available' => true,
625 ]
626 );
627
628 $this->add_control(
629 'animation_duration',
630 [
631 'label' => esc_html__( 'Animation Duration', 'elementor' ),
632 'type' => Controls_Manager::SELECT,
633 'default' => '',
634 'options' => [
635 'slow' => esc_html__( 'Slow', 'elementor' ),
636 '' => esc_html__( 'Normal', 'elementor' ),
637 'fast' => esc_html__( 'Fast', 'elementor' ),
638 ],
639 'prefix_class' => 'animated-',
640 'condition' => [
641 '_animation!' => '',
642 ],
643 ]
644 );
645
646 $this->add_control(
647 '_animation_delay',
648 [
649 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
650 'type' => Controls_Manager::NUMBER,
651 'default' => '',
652 'min' => 0,
653 'step' => 100,
654 'condition' => [
655 '_animation!' => '',
656 ],
657 'render_type' => 'none',
658 'frontend_available' => true,
659 ]
660 );
661
662 $this->end_controls_section();
663 }
664
665 /** Register the Background section.
666 *
667 * @return void
668 */
669 private function register_background_section() {
670 $this->start_controls_section(
671 '_section_background',
672 [
673 'label' => esc_html__( 'Background', 'elementor' ),
674 'tab' => Controls_Manager::TAB_ADVANCED,
675 ]
676 );
677
678 $this->start_controls_tabs( '_tabs_background' );
679
680 $this->start_controls_tab(
681 '_tab_background_normal',
682 [
683 'label' => esc_html__( 'Normal', 'elementor' ),
684 ]
685 );
686
687 $this->add_group_control(
688 Group_Control_Background::get_type(),
689 [
690 'name' => '_background',
691 'selector' => '{{WRAPPER}} > .elementor-widget-container',
692 'fields_options' => [
693 'image' => [
694 'background_lazyload' => [
695 'active' => true,
696 'keys' => [ '_background_image', 'url' ],
697 'selector' => '.elementor-widget-container',
698 ],
699 ],
700 ],
701 ]
702 );
703
704 $this->end_controls_tab();
705
706 $this->start_controls_tab(
707 '_tab_background_hover',
708 [
709 'label' => esc_html__( 'Hover', 'elementor' ),
710 ]
711 );
712
713 $this->add_group_control(
714 Group_Control_Background::get_type(),
715 [
716 'name' => '_background_hover',
717 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
718 ]
719 );
720
721 $this->add_control(
722 '_background_hover_transition',
723 [
724 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
725 'type' => Controls_Manager::SLIDER,
726 'range' => [
727 'px' => [
728 'min' => 0,
729 'max' => 3,
730 'step' => 0.1,
731 ],
732 ],
733 'render_type' => 'ui',
734 'separator' => 'before',
735 'selectors' => [
736 '{{WRAPPER}} > .elementor-widget-container' => 'transition: background {{SIZE}}s',
737 ],
738 ]
739 );
740
741 $this->end_controls_tab();
742
743 $this->end_controls_tabs();
744
745 $this->end_controls_section();
746 }
747
748 /**
749 * Register the Border section.
750 *
751 * @return void
752 */
753 private function register_border_section() {
754 $this->start_controls_section(
755 '_section_border',
756 [
757 'label' => esc_html__( 'Border', 'elementor' ),
758 'tab' => Controls_Manager::TAB_ADVANCED,
759 ]
760 );
761
762 $this->start_controls_tabs( '_tabs_border' );
763
764 $this->start_controls_tab(
765 '_tab_border_normal',
766 [
767 'label' => esc_html__( 'Normal', 'elementor' ),
768 ]
769 );
770
771 $this->add_group_control(
772 Group_Control_Border::get_type(),
773 [
774 'name' => '_border',
775 'selector' => '{{WRAPPER}} > .elementor-widget-container',
776 ]
777 );
778
779 $this->add_responsive_control(
780 '_border_radius',
781 [
782 'label' => esc_html__( 'Border Radius', 'elementor' ),
783 'type' => Controls_Manager::DIMENSIONS,
784 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
785 'selectors' => [
786 '{{WRAPPER}} > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
787 ],
788 ]
789 );
790
791 $this->add_group_control(
792 Group_Control_Box_Shadow::get_type(),
793 [
794 'name' => '_box_shadow',
795 'selector' => '{{WRAPPER}} > .elementor-widget-container',
796 ]
797 );
798
799 $this->end_controls_tab();
800
801 $this->start_controls_tab(
802 '_tab_border_hover',
803 [
804 'label' => esc_html__( 'Hover', 'elementor' ),
805 ]
806 );
807
808 $this->add_group_control(
809 Group_Control_Border::get_type(),
810 [
811 'name' => '_border_hover',
812 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
813 ]
814 );
815
816 $this->add_responsive_control(
817 '_border_radius_hover',
818 [
819 'label' => esc_html__( 'Border Radius', 'elementor' ),
820 'type' => Controls_Manager::DIMENSIONS,
821 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
822 'selectors' => [
823 '{{WRAPPER}}:hover > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
824 ],
825 ]
826 );
827
828 $this->add_group_control(
829 Group_Control_Box_Shadow::get_type(),
830 [
831 'name' => '_box_shadow_hover',
832 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
833 ]
834 );
835
836 $this->add_control(
837 '_border_hover_transition',
838 [
839 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
840 'type' => Controls_Manager::SLIDER,
841 'separator' => 'before',
842 'range' => [
843 'px' => [
844 'min' => 0,
845 'max' => 3,
846 'step' => 0.1,
847 ],
848 ],
849 'selectors' => [
850 '{{WRAPPER}} .elementor-widget-container' => 'transition: background {{_background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
851 ],
852 ]
853 );
854
855 $this->end_controls_tab();
856
857 $this->end_controls_tabs();
858
859 $this->end_controls_section();
860 }
861
862
863 /**
864 * Register the Mask section.
865 *
866 * @return void
867 */
868 private function register_masking_section() {
869 $this->start_controls_section(
870 '_section_masking',
871 [
872 'label' => esc_html__( 'Mask', 'elementor' ),
873 'tab' => Controls_Manager::TAB_ADVANCED,
874 ]
875 );
876
877 $this->add_control(
878 '_mask_switch',
879 [
880 'label' => esc_html__( 'Mask', 'elementor' ),
881 'type' => Controls_Manager::SWITCHER,
882 'label_on' => esc_html__( 'On', 'elementor' ),
883 'label_off' => esc_html__( 'Off', 'elementor' ),
884 'default' => '',
885 ]
886 );
887
888 $this->add_control(
889 '_mask_shape',
890 [
891 'label' => esc_html__( 'Shape', 'elementor' ),
892 'type' => Controls_Manager::SELECT,
893 'options' => $this->get_shapes(),
894 'default' => 'circle',
895 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( ' . ELEMENTOR_ASSETS_URL . '/mask-shapes/{{VALUE}}.svg );' ),
896 'condition' => [
897 '_mask_switch!' => '',
898 ],
899 ]
900 );
901
902 $this->add_control(
903 '_mask_image',
904 [
905 'label' => esc_html__( 'Image', 'elementor' ),
906 'type' => Controls_Manager::MEDIA,
907 'media_types' => [ 'image' ],
908 'should_include_svg_inline_option' => true,
909 'library_type' => 'image/svg+xml',
910 'dynamic' => [
911 'active' => true,
912 ],
913 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( {{URL}} );' ),
914 'condition' => [
915 '_mask_switch!' => '',
916 '_mask_shape' => 'custom',
917 ],
918 ]
919 );
920
921 $this->add_control(
922 '_mask_notice',
923 [
924 'type' => Controls_Manager::HIDDEN,
925 'raw' => esc_html__( 'Need More Shapes?', 'elementor' ) .
926 '<br>' .
927 sprintf(
928 /* translators: 1: Link open tag, 2: Link close tag. */
929 esc_html__( 'Explore additional Premium Shape packs and use them in your site. %1$sLearn More%2$s', 'elementor' ),
930 '<a target="_blank" href="https://go.elementor.com/mask-control">',
931 '</a>'
932 ),
933 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
934 'condition' => [
935 '_mask_switch!' => '',
936 ],
937 ]
938 );
939
940 $this->add_responsive_control(
941 '_mask_size',
942 [
943 'label' => esc_html__( 'Size', 'elementor' ),
944 'type' => Controls_Manager::SELECT,
945 'options' => [
946 'contain' => esc_html__( 'Fit', 'elementor' ),
947 'cover' => esc_html__( 'Fill', 'elementor' ),
948 'custom' => esc_html__( 'Custom', 'elementor' ),
949 ],
950 'default' => 'contain',
951 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{VALUE}};' ),
952 'condition' => [
953 '_mask_switch!' => '',
954 ],
955 ]
956 );
957
958 $this->add_responsive_control(
959 '_mask_size_scale',
960 [
961 'label' => esc_html__( 'Scale', 'elementor' ),
962 'type' => Controls_Manager::SLIDER,
963 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
964 'range' => [
965 'px' => [
966 'min' => 0,
967 'max' => 500,
968 ],
969 'em' => [
970 'min' => 0,
971 'max' => 100,
972 ],
973 '%' => [
974 'min' => 0,
975 'max' => 200,
976 ],
977 ],
978 'default' => [
979 'unit' => '%',
980 'size' => 100,
981 ],
982 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{SIZE}}{{UNIT}};' ),
983 'condition' => [
984 '_mask_switch!' => '',
985 '_mask_size' => 'custom',
986 ],
987 ]
988 );
989
990 $this->add_responsive_control(
991 '_mask_position',
992 [
993 'label' => esc_html__( 'Position', 'elementor' ),
994 'type' => Controls_Manager::SELECT,
995 'options' => [
996 'center center' => esc_html__( 'Center Center', 'elementor' ),
997 'center left' => esc_html__( 'Center Left', 'elementor' ),
998 'center right' => esc_html__( 'Center Right', 'elementor' ),
999 'top center' => esc_html__( 'Top Center', 'elementor' ),
1000 'top left' => esc_html__( 'Top Left', 'elementor' ),
1001 'top right' => esc_html__( 'Top Right', 'elementor' ),
1002 'bottom center' => esc_html__( 'Bottom Center', 'elementor' ),
1003 'bottom left' => esc_html__( 'Bottom Left', 'elementor' ),
1004 'bottom right' => esc_html__( 'Bottom Right', 'elementor' ),
1005 'custom' => esc_html__( 'Custom', 'elementor' ),
1006 ],
1007 'default' => 'center center',
1008 'selectors' => $this->get_mask_selectors( '-webkit-mask-position: {{VALUE}};' ),
1009 'condition' => [
1010 '_mask_switch!' => '',
1011 ],
1012 ]
1013 );
1014
1015 $this->add_responsive_control(
1016 '_mask_position_x',
1017 [
1018 'label' => esc_html__( 'X Position', 'elementor' ),
1019 'type' => Controls_Manager::SLIDER,
1020 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1021 'range' => [
1022 'px' => [
1023 'min' => -500,
1024 'max' => 500,
1025 ],
1026 'em' => [
1027 'min' => -100,
1028 'max' => 100,
1029 ],
1030 '%' => [
1031 'min' => -100,
1032 'max' => 100,
1033 ],
1034 'vw' => [
1035 'min' => -100,
1036 'max' => 100,
1037 ],
1038 ],
1039 'default' => [
1040 'unit' => '%',
1041 'size' => 0,
1042 ],
1043 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-x: {{SIZE}}{{UNIT}};' ),
1044 'condition' => [
1045 '_mask_switch!' => '',
1046 '_mask_position' => 'custom',
1047 ],
1048 ]
1049 );
1050
1051 $this->add_responsive_control(
1052 '_mask_position_y',
1053 [
1054 'label' => esc_html__( 'Y Position', 'elementor' ),
1055 'type' => Controls_Manager::SLIDER,
1056 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1057 'range' => [
1058 'px' => [
1059 'min' => -500,
1060 'max' => 500,
1061 ],
1062 'em' => [
1063 'min' => -100,
1064 'max' => 100,
1065 ],
1066 '%' => [
1067 'min' => -100,
1068 'max' => 100,
1069 ],
1070 'vw' => [
1071 'min' => -100,
1072 'max' => 100,
1073 ],
1074 ],
1075 'default' => [
1076 'unit' => '%',
1077 'size' => 0,
1078 ],
1079 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-y: {{SIZE}}{{UNIT}};' ),
1080 'condition' => [
1081 '_mask_switch!' => '',
1082 '_mask_position' => 'custom',
1083 ],
1084 ]
1085 );
1086
1087 $this->add_responsive_control(
1088 '_mask_repeat',
1089 [
1090 'label' => esc_html__( 'Repeat', 'elementor' ),
1091 'type' => Controls_Manager::SELECT,
1092 'options' => [
1093 'no-repeat' => esc_html__( 'No-repeat', 'elementor' ),
1094 'repeat' => esc_html__( 'Repeat', 'elementor' ),
1095 'repeat-x' => esc_html__( 'Repeat-x', 'elementor' ),
1096 'repeat-Y' => esc_html__( 'Repeat-y', 'elementor' ),
1097 'round' => esc_html__( 'Round', 'elementor' ),
1098 'space' => esc_html__( 'Space', 'elementor' ),
1099 ],
1100 'default' => 'no-repeat',
1101 'selectors' => $this->get_mask_selectors( '-webkit-mask-repeat: {{VALUE}};' ),
1102 'condition' => [
1103 '_mask_switch!' => '',
1104 '_mask_size!' => 'cover',
1105 ],
1106 ]
1107 );
1108
1109 $this->end_controls_section();
1110 }
1111
1112
1113 /**
1114 * Register the Responsive section.
1115 *
1116 * @return void
1117 */
1118 private function register_responsive_section() {
1119 $this->start_controls_section(
1120 '_section_responsive',
1121 [
1122 'label' => esc_html__( 'Responsive', 'elementor' ),
1123 'tab' => Controls_Manager::TAB_ADVANCED,
1124 ]
1125 );
1126
1127 $this->add_control(
1128 'responsive_description',
1129 [
1130 'raw' => sprintf(
1131 /* translators: 1: Link open tag, 2: Link close tag. */
1132 esc_html__( 'Responsive visibility will take effect only on %1$s preview mode %2$s or live page, and not while editing in Elementor.', 'elementor' ),
1133 '<a href="javascript: $e.run( \'panel/close\' )">',
1134 '</a>'
1135 ),
1136 'type' => Controls_Manager::RAW_HTML,
1137 'content_classes' => 'elementor-descriptor',
1138 ]
1139 );
1140
1141 $this->add_hidden_device_controls();
1142
1143 $this->end_controls_section();
1144 }
1145
1146 /**
1147 * Register common widget controls.
1148 *
1149 * Adds different input fields to allow the user to change and customize the widget settings.
1150 *
1151 * @since 3.1.0
1152 * @access protected
1153 */
1154 protected function register_controls() {
1155 $this->register_layout_section();
1156
1157 $this->register_effects_section();
1158
1159 $this->register_transform_section();
1160
1161 $this->register_background_section();
1162
1163 $this->register_border_section();
1164
1165 $this->register_masking_section();
1166
1167 $this->register_responsive_section();
1168
1169 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1170
1171 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1172 }
1173 }
1174