PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.1 4.3.0 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 All 454 releases
elementor / modules / atomic-widgets / css-converter / converters / transform-origin-property-converter.php

transform-origin-property-converter.php in Elementor Website Builder – more than just a page builder 4.3.1, at modules/atomic-widgets/css-converter/converters/transform-origin-property-converter.php

180 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\AtomicWidgets\CssConverter\Converters;
4
5 use Elementor\Modules\AtomicWidgets\CssConverter\Conversion_Context;
6 use Elementor\Modules\AtomicWidgets\CssConverter\Property_Converter_Base;
7 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Css_Token_Splitter;
8 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Size_Value_Parser;
9 use Elementor\Modules\AtomicWidgets\PropTypes\Size_Prop_Type;
10 use Elementor\Modules\AtomicWidgets\PropTypes\Transform\Transform_Origin_Prop_Type;
11 use Elementor\Modules\AtomicWidgets\PropTypes\Transform\Transform_Prop_Type;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit; // Exit if accessed directly.
15 }
16
17 /**
18 * Converter for the `transform-origin` CSS property.
19 *
20 * Maps into the `transform-origin` field nested inside the `transform` Prop_Type
21 * (merging with any prior transform fields already in the context).
22 *
23 * Accepted CSS syntax (1, 2, or 3 tokens, order = x y z):
24 * - keywords: left | right | center | top | bottom
25 * - length: <number><px|em|rem>
26 * - percentage: <number>%
27 *
28 * Unit rules:
29 * - x/y: % px em rem
30 * - z: px em rem (no %)
31 *
32 * Anything else declines the entire declaration to customCss.
33 */
34 class Transform_Origin_Property_Converter extends Property_Converter_Base {
35 const XY_UNITS = [ '%', 'px', 'em', 'rem' ];
36 const Z_UNITS = [ 'px', 'em', 'rem' ];
37
38 const X_KEYWORDS = [
39 'left' => 0,
40 'center' => 50,
41 'right' => 100,
42 ];
43 const Y_KEYWORDS = [
44 'top' => 0,
45 'center' => 50,
46 'bottom' => 100,
47 ];
48
49 const CENTER = [
50 'size' => 50,
51 'unit' => '%',
52 ];
53
54 protected function get_supported_properties(): array {
55 return [ 'transform-origin' ];
56 }
57
58 protected function do_convert( Conversion_Context $context, array $rule ): bool {
59 $axes = $this->parse( trim( $rule['value'] ) );
60
61 if ( null === $axes ) {
62 return false;
63 }
64
65 $existing = $context->get_prop( 'transform' );
66 $fields = $this->current_fields( $existing );
67 $fields['transform-origin'] = Transform_Origin_Prop_Type::generate( [
68 'x' => Size_Prop_Type::generate( $axes['x'] ),
69 'y' => Size_Prop_Type::generate( $axes['y'] ),
70 'z' => Size_Prop_Type::generate( $axes['z'] ),
71 ] );
72
73 $context->set_prop( 'transform', Transform_Prop_Type::generate( $fields ) );
74
75 return true;
76 }
77
78 private function parse( string $value ): ?array {
79 $tokens = Css_Token_Splitter::split_by_whitespace( $value );
80 $count = count( $tokens );
81
82 if ( $count < 1 || $count > 3 ) {
83 return null;
84 }
85
86 [ $x, $y ] = $this->parse_xy( $tokens );
87
88 if ( null === $x || null === $y ) {
89 return null;
90 }
91
92 $z = 3 === $count ? $this->parse_z( $tokens[2] ) : [
93 'size' => 0,
94 'unit' => 'px',
95 ];
96
97 if ( null === $z ) {
98 return null;
99 }
100
101 return [
102 'x' => $x,
103 'y' => $y,
104 'z' => $z,
105 ];
106 }
107
108 private function parse_xy( array $tokens ): array {
109 if ( 1 === count( $tokens ) ) {
110 return $this->parse_single_xy( strtolower( $tokens[0] ) );
111 }
112
113 return [
114 $this->parse_axis( strtolower( $tokens[0] ), self::X_KEYWORDS ),
115 $this->parse_axis( strtolower( $tokens[1] ), self::Y_KEYWORDS ),
116 ];
117 }
118
119 private function parse_single_xy( string $token ): array {
120 if ( isset( self::X_KEYWORDS[ $token ] ) && ! isset( self::Y_KEYWORDS[ $token ] ) ) {
121 return [ $this->keyword_size( self::X_KEYWORDS[ $token ] ), self::CENTER ];
122 }
123
124 if ( isset( self::Y_KEYWORDS[ $token ] ) && ! isset( self::X_KEYWORDS[ $token ] ) ) {
125 return [ self::CENTER, $this->keyword_size( self::Y_KEYWORDS[ $token ] ) ];
126 }
127
128 if ( 'center' === $token ) {
129 return [ self::CENTER, self::CENTER ];
130 }
131
132 $size = $this->xy_size( $token );
133
134 return null === $size ? [ null, null ] : [ $size, self::CENTER ];
135 }
136
137 private function parse_axis( string $token, array $keywords ): ?array {
138 if ( isset( $keywords[ $token ] ) ) {
139 return $this->keyword_size( $keywords[ $token ] );
140 }
141
142 return $this->xy_size( $token );
143 }
144
145 private function xy_size( string $token ): ?array {
146 $parsed = Size_Value_Parser::parse( $token );
147
148 if ( null === $parsed || ! in_array( $parsed['unit'], self::XY_UNITS, true ) ) {
149 return null;
150 }
151
152 return $parsed;
153 }
154
155 private function parse_z( string $token ): ?array {
156 $parsed = Size_Value_Parser::parse( $token );
157
158 if ( null === $parsed || ! in_array( $parsed['unit'], self::Z_UNITS, true ) ) {
159 return null;
160 }
161
162 return $parsed;
163 }
164
165 private function keyword_size( int $percent ): array {
166 return [
167 'size' => $percent,
168 'unit' => '%',
169 ];
170 }
171
172 private function current_fields( $existing ): array {
173 if ( is_array( $existing ) && isset( $existing['value'] ) ) {
174 return $existing['value'];
175 }
176
177 return [];
178 }
179 }
180