PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.2
Elementor Website Builder – more than just a page builder v4.3.2
4.3.2 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 All 455 releases
elementor / modules / atomic-widgets / css-converter / converters / object-field-merge-converter.php

object-field-merge-converter.php in Elementor Website Builder – more than just a page builder 4.3.2, at modules/atomic-widgets/css-converter/converters/object-field-merge-converter.php

136 lines 4.6 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
8 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Css_Token_Splitter;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 /**
15 * Converter for a single scalar longhand that contributes one field to a flat aggregate object prop,
16 * e.g. background-color -> the `color` field of `background` (Background), background-clip -> `clip`.
17 * One instance per input property.
18 *
19 * The target object is accumulated in the shared context across sibling declarations: each instance
20 * reads the current target prop, re-populates it when it is already this object, or starts a fresh one
21 * otherwise, then writes the single field it owns. Unlike Object_Side_Merge_Converter there is no
22 * single-member seeding because the aggregate has no scalar union member.
23 *
24 * The leaf is produced by the injected leaf prop type's generate(). An optional allowlist rejects
25 * out-of-enum values, and an optional single-token guard rejects multi-token values (a faithful single
26 * color must be one paren-aware token). A rejected value declines the declaration (-> custom_css) and
27 * leaves the accumulated object untouched.
28 */
29 class Object_Field_Merge_Converter extends Property_Converter_Base {
30 private string $property;
31 private string $target_property;
32 private string $type_key;
33 private string $field_key;
34
35 /**
36 * @var class-string
37 */
38 private string $leaf_prop_type;
39
40 /**
41 * @var class-string
42 */
43 private string $object_prop_type;
44
45 /**
46 * @var string[]|null
47 */
48 private ?array $allowed_values;
49
50 private bool $single_token_only;
51
52 /**
53 * @param string $property The input longhand this converter owns (e.g. background-color).
54 * @param string $target_property The aggregate prop it contributes to (e.g. background).
55 * @param string $type_key The aggregate object's $$type (e.g. background).
56 * @param string $field_key The object field this longhand fills (e.g. color).
57 * @param string $leaf_prop_type Prop_Type class whose generate() wraps the leaf value.
58 * @param string $object_prop_type Object_Prop_Type class used to wrap the merged fields.
59 * @param string[]|null $allowed_values Enum allowlist for the leaf, or null to accept any value.
60 * @param bool $single_token_only Reject values that split into more than one top-level token.
61 */
62 public function __construct(
63 string $property,
64 string $target_property,
65 string $type_key,
66 string $field_key,
67 string $leaf_prop_type,
68 string $object_prop_type,
69 ?array $allowed_values = null,
70 bool $single_token_only = false
71 ) {
72 $this->property = $property;
73 $this->target_property = $target_property;
74 $this->type_key = $type_key;
75 $this->field_key = $field_key;
76 $this->leaf_prop_type = $leaf_prop_type;
77 $this->object_prop_type = $object_prop_type;
78 $this->allowed_values = $allowed_values;
79 $this->single_token_only = $single_token_only;
80 }
81
82 protected function get_supported_properties(): array {
83 return [ $this->property ];
84 }
85
86 protected function convert_null( Conversion_Context $context, array $rule ): bool {
87 $fields = $this->current_fields( $context->get_prop( $this->target_property ) );
88 $fields[ $this->field_key ] = null;
89
90 $context->set_prop( $this->target_property, ( $this->object_prop_type )::generate( $fields ) );
91
92 return true;
93 }
94
95 protected function do_convert( Conversion_Context $context, array $rule ): bool {
96 $value = trim( $rule['value'] );
97
98 if ( '' === $value ) {
99 return false;
100 }
101
102 if ( null !== $this->allowed_values && ! in_array( $value, $this->allowed_values, true ) ) {
103 return false;
104 }
105
106 if ( $this->single_token_only && 1 !== count( Css_Token_Splitter::split_by_whitespace( $value ) ) ) {
107 return false;
108 }
109
110 $fields = $this->current_fields( $context->get_prop( $this->target_property ) );
111 $fields[ $this->field_key ] = ( $this->leaf_prop_type )::generate( $value );
112
113 $context->set_prop( $this->target_property, ( $this->object_prop_type )::generate( $fields ) );
114
115 return true;
116 }
117
118 /**
119 * @param mixed $existing The current target prop value, if any.
120 * @return array<string, array> Field key -> leaf PropValue.
121 */
122 private function current_fields( $existing ): array {
123 if ( ! is_array( $existing ) ) {
124 return [];
125 }
126
127 $type = $existing['$$type'] ?? null;
128
129 if ( $this->type_key === $type && is_array( $existing['value'] ?? null ) ) {
130 return $existing['value'];
131 }
132
133 return [];
134 }
135 }
136