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

1,172 lines 28.4 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 $this->end_controls_section();
601 }
602
603 /**
604 * Register the Motion Effects section.
605 *
606 * @return void
607 */
608 private function register_effects_section() {
609 $this->start_controls_section(
610 'section_effects',
611 [
612 'label' => esc_html__( 'Motion Effects', 'elementor' ),
613 'tab' => Controls_Manager::TAB_ADVANCED,
614 ]
615 );
616
617 $this->add_responsive_control(
618 '_animation',
619 [
620 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
621 'type' => Controls_Manager::ANIMATION,
622 'frontend_available' => true,
623 ]
624 );
625
626 $this->add_control(
627 'animation_duration',
628 [
629 'label' => esc_html__( 'Animation Duration', 'elementor' ),
630 'type' => Controls_Manager::SELECT,
631 'default' => '',
632 'options' => [
633 'slow' => esc_html__( 'Slow', 'elementor' ),
634 '' => esc_html__( 'Normal', 'elementor' ),
635 'fast' => esc_html__( 'Fast', 'elementor' ),
636 ],
637 'prefix_class' => 'animated-',
638 'condition' => [
639 '_animation!' => '',
640 ],
641 ]
642 );
643
644 $this->add_control(
645 '_animation_delay',
646 [
647 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
648 'type' => Controls_Manager::NUMBER,
649 'default' => '',
650 'min' => 0,
651 'step' => 100,
652 'condition' => [
653 '_animation!' => '',
654 ],
655 'render_type' => 'none',
656 'frontend_available' => true,
657 ]
658 );
659
660 $this->end_controls_section();
661 }
662
663 /** Register the Background section.
664 *
665 * @return void
666 */
667 private function register_background_section() {
668 $this->start_controls_section(
669 '_section_background',
670 [
671 'label' => esc_html__( 'Background', 'elementor' ),
672 'tab' => Controls_Manager::TAB_ADVANCED,
673 ]
674 );
675
676 $this->start_controls_tabs( '_tabs_background' );
677
678 $this->start_controls_tab(
679 '_tab_background_normal',
680 [
681 'label' => esc_html__( 'Normal', 'elementor' ),
682 ]
683 );
684
685 $this->add_group_control(
686 Group_Control_Background::get_type(),
687 [
688 'name' => '_background',
689 'selector' => '{{WRAPPER}} > .elementor-widget-container',
690 'fields_options' => [
691 'image' => [
692 'background_lazyload' => [
693 'active' => true,
694 'keys' => [ '_background_image', 'url' ],
695 'selector' => '.elementor-widget-container',
696 ],
697 ],
698 ],
699 ]
700 );
701
702 $this->end_controls_tab();
703
704 $this->start_controls_tab(
705 '_tab_background_hover',
706 [
707 'label' => esc_html__( 'Hover', 'elementor' ),
708 ]
709 );
710
711 $this->add_group_control(
712 Group_Control_Background::get_type(),
713 [
714 'name' => '_background_hover',
715 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
716 ]
717 );
718
719 $this->add_control(
720 '_background_hover_transition',
721 [
722 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
723 'type' => Controls_Manager::SLIDER,
724 'range' => [
725 'px' => [
726 'min' => 0,
727 'max' => 3,
728 'step' => 0.1,
729 ],
730 ],
731 'render_type' => 'ui',
732 'separator' => 'before',
733 'selectors' => [
734 '{{WRAPPER}} > .elementor-widget-container' => 'transition: background {{SIZE}}s',
735 ],
736 ]
737 );
738
739 $this->end_controls_tab();
740
741 $this->end_controls_tabs();
742
743 $this->end_controls_section();
744 }
745
746 /**
747 * Register the Border section.
748 *
749 * @return void
750 */
751 private function register_border_section() {
752 $this->start_controls_section(
753 '_section_border',
754 [
755 'label' => esc_html__( 'Border', 'elementor' ),
756 'tab' => Controls_Manager::TAB_ADVANCED,
757 ]
758 );
759
760 $this->start_controls_tabs( '_tabs_border' );
761
762 $this->start_controls_tab(
763 '_tab_border_normal',
764 [
765 'label' => esc_html__( 'Normal', 'elementor' ),
766 ]
767 );
768
769 $this->add_group_control(
770 Group_Control_Border::get_type(),
771 [
772 'name' => '_border',
773 'selector' => '{{WRAPPER}} > .elementor-widget-container',
774 ]
775 );
776
777 $this->add_responsive_control(
778 '_border_radius',
779 [
780 'label' => esc_html__( 'Border Radius', 'elementor' ),
781 'type' => Controls_Manager::DIMENSIONS,
782 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
783 'selectors' => [
784 '{{WRAPPER}} > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
785 ],
786 ]
787 );
788
789 $this->add_group_control(
790 Group_Control_Box_Shadow::get_type(),
791 [
792 'name' => '_box_shadow',
793 'selector' => '{{WRAPPER}} > .elementor-widget-container',
794 ]
795 );
796
797 $this->end_controls_tab();
798
799 $this->start_controls_tab(
800 '_tab_border_hover',
801 [
802 'label' => esc_html__( 'Hover', 'elementor' ),
803 ]
804 );
805
806 $this->add_group_control(
807 Group_Control_Border::get_type(),
808 [
809 'name' => '_border_hover',
810 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
811 ]
812 );
813
814 $this->add_responsive_control(
815 '_border_radius_hover',
816 [
817 'label' => esc_html__( 'Border Radius', 'elementor' ),
818 'type' => Controls_Manager::DIMENSIONS,
819 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
820 'selectors' => [
821 '{{WRAPPER}}:hover > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
822 ],
823 ]
824 );
825
826 $this->add_group_control(
827 Group_Control_Box_Shadow::get_type(),
828 [
829 'name' => '_box_shadow_hover',
830 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
831 ]
832 );
833
834 $this->add_control(
835 '_border_hover_transition',
836 [
837 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
838 'type' => Controls_Manager::SLIDER,
839 'separator' => 'before',
840 'range' => [
841 'px' => [
842 'min' => 0,
843 'max' => 3,
844 'step' => 0.1,
845 ],
846 ],
847 'selectors' => [
848 '{{WRAPPER}} .elementor-widget-container' => 'transition: background {{_background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
849 ],
850 ]
851 );
852
853 $this->end_controls_tab();
854
855 $this->end_controls_tabs();
856
857 $this->end_controls_section();
858 }
859
860
861 /**
862 * Register the Mask section.
863 *
864 * @return void
865 */
866 private function register_masking_section() {
867 $this->start_controls_section(
868 '_section_masking',
869 [
870 'label' => esc_html__( 'Mask', 'elementor' ),
871 'tab' => Controls_Manager::TAB_ADVANCED,
872 ]
873 );
874
875 $this->add_control(
876 '_mask_switch',
877 [
878 'label' => esc_html__( 'Mask', 'elementor' ),
879 'type' => Controls_Manager::SWITCHER,
880 'label_on' => esc_html__( 'On', 'elementor' ),
881 'label_off' => esc_html__( 'Off', 'elementor' ),
882 'default' => '',
883 ]
884 );
885
886 $this->add_control(
887 '_mask_shape',
888 [
889 'label' => esc_html__( 'Shape', 'elementor' ),
890 'type' => Controls_Manager::SELECT,
891 'options' => $this->get_shapes(),
892 'default' => 'circle',
893 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( ' . ELEMENTOR_ASSETS_URL . '/mask-shapes/{{VALUE}}.svg );' ),
894 'condition' => [
895 '_mask_switch!' => '',
896 ],
897 ]
898 );
899
900 $this->add_control(
901 '_mask_image',
902 [
903 'label' => esc_html__( 'Image', 'elementor' ),
904 'type' => Controls_Manager::MEDIA,
905 'media_types' => [ 'image' ],
906 'should_include_svg_inline_option' => true,
907 'library_type' => 'image/svg+xml',
908 'dynamic' => [
909 'active' => true,
910 ],
911 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( {{URL}} );' ),
912 'condition' => [
913 '_mask_switch!' => '',
914 '_mask_shape' => 'custom',
915 ],
916 ]
917 );
918
919 $this->add_control(
920 '_mask_notice',
921 [
922 'type' => Controls_Manager::HIDDEN,
923 'raw' => esc_html__( 'Need More Shapes?', 'elementor' ) .
924 '<br>' .
925 sprintf(
926 /* translators: 1: Link open tag, 2: Link close tag. */
927 esc_html__( 'Explore additional Premium Shape packs and use them in your site. %1$sLearn More%2$s', 'elementor' ),
928 '<a target="_blank" href="https://go.elementor.com/mask-control">',
929 '</a>'
930 ),
931 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
932 'condition' => [
933 '_mask_switch!' => '',
934 ],
935 ]
936 );
937
938 $this->add_responsive_control(
939 '_mask_size',
940 [
941 'label' => esc_html__( 'Size', 'elementor' ),
942 'type' => Controls_Manager::SELECT,
943 'options' => [
944 'contain' => esc_html__( 'Fit', 'elementor' ),
945 'cover' => esc_html__( 'Fill', 'elementor' ),
946 'custom' => esc_html__( 'Custom', 'elementor' ),
947 ],
948 'default' => 'contain',
949 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{VALUE}};' ),
950 'condition' => [
951 '_mask_switch!' => '',
952 ],
953 ]
954 );
955
956 $this->add_responsive_control(
957 '_mask_size_scale',
958 [
959 'label' => esc_html__( 'Scale', 'elementor' ),
960 'type' => Controls_Manager::SLIDER,
961 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
962 'range' => [
963 'px' => [
964 'min' => 0,
965 'max' => 500,
966 ],
967 'em' => [
968 'min' => 0,
969 'max' => 100,
970 ],
971 '%' => [
972 'min' => 0,
973 'max' => 200,
974 ],
975 ],
976 'default' => [
977 'unit' => '%',
978 'size' => 100,
979 ],
980 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{SIZE}}{{UNIT}};' ),
981 'condition' => [
982 '_mask_switch!' => '',
983 '_mask_size' => 'custom',
984 ],
985 ]
986 );
987
988 $this->add_responsive_control(
989 '_mask_position',
990 [
991 'label' => esc_html__( 'Position', 'elementor' ),
992 'type' => Controls_Manager::SELECT,
993 'options' => [
994 'center center' => esc_html__( 'Center Center', 'elementor' ),
995 'center left' => esc_html__( 'Center Left', 'elementor' ),
996 'center right' => esc_html__( 'Center Right', 'elementor' ),
997 'top center' => esc_html__( 'Top Center', 'elementor' ),
998 'top left' => esc_html__( 'Top Left', 'elementor' ),
999 'top right' => esc_html__( 'Top Right', 'elementor' ),
1000 'bottom center' => esc_html__( 'Bottom Center', 'elementor' ),
1001 'bottom left' => esc_html__( 'Bottom Left', 'elementor' ),
1002 'bottom right' => esc_html__( 'Bottom Right', 'elementor' ),
1003 'custom' => esc_html__( 'Custom', 'elementor' ),
1004 ],
1005 'default' => 'center center',
1006 'selectors' => $this->get_mask_selectors( '-webkit-mask-position: {{VALUE}};' ),
1007 'condition' => [
1008 '_mask_switch!' => '',
1009 ],
1010 ]
1011 );
1012
1013 $this->add_responsive_control(
1014 '_mask_position_x',
1015 [
1016 'label' => esc_html__( 'X Position', 'elementor' ),
1017 'type' => Controls_Manager::SLIDER,
1018 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1019 'range' => [
1020 'px' => [
1021 'min' => -500,
1022 'max' => 500,
1023 ],
1024 'em' => [
1025 'min' => -100,
1026 'max' => 100,
1027 ],
1028 '%' => [
1029 'min' => -100,
1030 'max' => 100,
1031 ],
1032 'vw' => [
1033 'min' => -100,
1034 'max' => 100,
1035 ],
1036 ],
1037 'default' => [
1038 'unit' => '%',
1039 'size' => 0,
1040 ],
1041 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-x: {{SIZE}}{{UNIT}};' ),
1042 'condition' => [
1043 '_mask_switch!' => '',
1044 '_mask_position' => 'custom',
1045 ],
1046 ]
1047 );
1048
1049 $this->add_responsive_control(
1050 '_mask_position_y',
1051 [
1052 'label' => esc_html__( 'Y Position', 'elementor' ),
1053 'type' => Controls_Manager::SLIDER,
1054 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1055 'range' => [
1056 'px' => [
1057 'min' => -500,
1058 'max' => 500,
1059 ],
1060 'em' => [
1061 'min' => -100,
1062 'max' => 100,
1063 ],
1064 '%' => [
1065 'min' => -100,
1066 'max' => 100,
1067 ],
1068 'vw' => [
1069 'min' => -100,
1070 'max' => 100,
1071 ],
1072 ],
1073 'default' => [
1074 'unit' => '%',
1075 'size' => 0,
1076 ],
1077 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-y: {{SIZE}}{{UNIT}};' ),
1078 'condition' => [
1079 '_mask_switch!' => '',
1080 '_mask_position' => 'custom',
1081 ],
1082 ]
1083 );
1084
1085 $this->add_responsive_control(
1086 '_mask_repeat',
1087 [
1088 'label' => esc_html__( 'Repeat', 'elementor' ),
1089 'type' => Controls_Manager::SELECT,
1090 'options' => [
1091 'no-repeat' => esc_html__( 'No-repeat', 'elementor' ),
1092 'repeat' => esc_html__( 'Repeat', 'elementor' ),
1093 'repeat-x' => esc_html__( 'Repeat-x', 'elementor' ),
1094 'repeat-Y' => esc_html__( 'Repeat-y', 'elementor' ),
1095 'round' => esc_html__( 'Round', 'elementor' ),
1096 'space' => esc_html__( 'Space', 'elementor' ),
1097 ],
1098 'default' => 'no-repeat',
1099 'selectors' => $this->get_mask_selectors( '-webkit-mask-repeat: {{VALUE}};' ),
1100 'condition' => [
1101 '_mask_switch!' => '',
1102 '_mask_size!' => 'cover',
1103 ],
1104 ]
1105 );
1106
1107 $this->end_controls_section();
1108 }
1109
1110
1111 /**
1112 * Register the Responsive section.
1113 *
1114 * @return void
1115 */
1116 private function register_responsive_section() {
1117 $this->start_controls_section(
1118 '_section_responsive',
1119 [
1120 'label' => esc_html__( 'Responsive', 'elementor' ),
1121 'tab' => Controls_Manager::TAB_ADVANCED,
1122 ]
1123 );
1124
1125 $this->add_control(
1126 'responsive_description',
1127 [
1128 'raw' => sprintf(
1129 /* translators: 1: Link open tag, 2: Link close tag. */
1130 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' ),
1131 '<a href="javascript: $e.run( \'panel/close\' )">',
1132 '</a>'
1133 ),
1134 'type' => Controls_Manager::RAW_HTML,
1135 'content_classes' => 'elementor-descriptor',
1136 ]
1137 );
1138
1139 $this->add_hidden_device_controls();
1140
1141 $this->end_controls_section();
1142 }
1143
1144 /**
1145 * Register common widget controls.
1146 *
1147 * Adds different input fields to allow the user to change and customize the widget settings.
1148 *
1149 * @since 3.1.0
1150 * @access protected
1151 */
1152 protected function register_controls() {
1153 $this->register_layout_section();
1154
1155 $this->register_effects_section();
1156
1157 $this->register_transform_section();
1158
1159 $this->register_background_section();
1160
1161 $this->register_border_section();
1162
1163 $this->register_masking_section();
1164
1165 $this->register_responsive_section();
1166
1167 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1168
1169 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1170 }
1171 }
1172