PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / helpers / FrmCssScopeHelper.php

FrmCssScopeHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.26.1, at classes/helpers/FrmCssScopeHelper.php

263 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmCssScopeHelper {
7
8 /**
9 * Nest the CSS.
10 * This function nests the CSS by adding the class name prefix to the selectors.
11 *
12 * @param string $css
13 * @param string $class_name
14 *
15 * @return string
16 */
17 public function nest( $css, $class_name ) {
18 // Remove CSS comments but preserve newlines
19 $css = preg_replace( '/\/\*.*?\*\//s', '', $css );
20
21 $output = array();
22 $css = trim( $css );
23 $length = strlen( $css );
24 $i = 0;
25 $buffer = '';
26
27 while ( $i < $length ) {
28 $char = $css[ $i ];
29
30 if ( '@' === $char ) {
31 $brace_pos = strpos( $css, '{', $i );
32
33 if ( false === $brace_pos ) {
34 $buffer .= $char;
35 ++$i;
36 continue;
37 }
38
39 $rule = substr( $css, $i, $brace_pos - $i );
40 $closing_brace = $this->find_matching_brace( $css, $brace_pos );
41 $inner_content = substr( $css, $brace_pos + 1, $closing_brace - $brace_pos - 1 );
42
43 // Don't nest keyframes content
44 if ( strpos( $rule, '@keyframes' ) !== false ) {
45 $output[] = "\n" . $rule . ' {' . $inner_content . '}' . "\n";
46 } else {
47 $output[] = "\n" . $rule . ' {';
48 $output[] = $this->nest( $inner_content, $class_name );
49 $output[] = '}' . "\n";
50 }
51
52 $i = $closing_brace + 1;
53 $buffer = '';
54 continue;
55 }//end if
56
57 if ( '{' === $char ) {
58 $selector = trim( $buffer );
59 $closing_brace = $this->find_matching_brace( $css, $i );
60 $declarations = substr( $css, $i + 1, $closing_brace - $i - 1 );
61
62 // Preserve indentation and formatting of declarations
63 $declarations = $this->preserve_declaration_formatting( $declarations );
64
65 if ( '' !== $selector && '' !== trim( $declarations ) ) {
66 // Handle multiple selectors
67 $selectors = array_map( 'trim', explode( ',', $selector ) );
68 $prefixed_selectors = array();
69
70 foreach ( $selectors as $single_selector ) {
71 if ( '' !== $single_selector ) {
72 $prefixed_selectors[] = '.' . $class_name . ' ' . $single_selector;
73 }
74 }
75
76 if ( ! empty( $prefixed_selectors ) ) {
77 $output[] = "\n" . implode( ',' . "\n", $prefixed_selectors ) . ' {' . $declarations . '}' . "\n";
78 }
79 }
80
81 $i = $closing_brace + 1;
82 $buffer = '';
83 continue;
84 }//end if
85
86 $buffer .= $char;
87 ++$i;
88 }//end while
89
90 return implode( '', $output );
91 }
92
93 /**
94 * Unnest the CSS.
95 * This function unnests the CSS by removing the class name prefix from the selectors.
96 *
97 * @param string $css
98 * @param string $class_name
99 *
100 * @return string
101 */
102 public function unnest( $css, $class_name ) {
103 // Remove CSS comments but preserve newlines
104 $css = preg_replace( '/\/\*.*?\*\//s', '', $css );
105
106 $output = array();
107 $css = trim( $css );
108 $length = strlen( $css );
109 $i = 0;
110 $buffer = '';
111 $prefix = '.' . $class_name . ' ';
112 $prefix_length = strlen( $prefix );
113
114 while ( $i < $length ) {
115 $char = $css[ $i ];
116
117 if ( '@' === $char ) {
118 $brace_pos = strpos( $css, '{', $i );
119
120 if ( false === $brace_pos ) {
121 $buffer .= $char;
122 ++$i;
123
124 continue;
125 }
126
127 $rule = substr( $css, $i, $brace_pos - $i );
128 $closing_brace = $this->find_matching_brace( $css, $brace_pos );
129 $inner_content = substr( $css, $brace_pos + 1, $closing_brace - $brace_pos - 1 );
130
131 $output[] = "\n" . $rule . ' {';
132 $output[] = $this->unnest( $inner_content, $class_name );
133 $output[] = '}' . "\n";
134
135 $i = $closing_brace + 1;
136 $buffer = '';
137 continue;
138 }//end if
139
140 if ( '{' === $char ) {
141 $selector = trim( $buffer );
142 $closing_brace = $this->find_matching_brace( $css, $i );
143 $declarations = substr( $css, $i + 1, $closing_brace - $i - 1 );
144
145 // Preserve indentation and formatting of declarations
146 $declarations = $this->preserve_declaration_formatting( $declarations );
147
148 if ( '' !== $selector && '' !== trim( $declarations ) ) {
149 // Handle multiple selectors
150 $selectors = array_filter(
151 array_map( 'trim', explode( ',', $selector ) ),
152 function ( $s ) {
153 return '' !== $s;
154 }
155 );
156 $unprefixed_selectors = array();
157
158 foreach ( $selectors as $single_selector ) {
159 $unprefixed_selectors[] = 0 === strpos( $single_selector, $prefix )
160 ? trim( substr( $single_selector, $prefix_length ) )
161 : $single_selector;
162 }
163
164 if ( ! empty( $unprefixed_selectors ) ) {
165 $output[] = "\n" . implode( ',' . "\n", $unprefixed_selectors ) . ' {' . $declarations . '}' . "\n";
166 }
167 }
168
169 $i = $closing_brace + 1;
170 $buffer = '';
171 continue;
172 }//end if
173
174 $buffer .= $char;
175 ++$i;
176 }//end while
177 return implode( '', $output );
178 }
179
180 /**
181 * Preserve declaration formatting with proper indentation.
182 *
183 * @param string $declarations
184 *
185 * @return string
186 */
187 private function preserve_declaration_formatting( $declarations ) {
188 // Trim the entire block but keep internal structure
189 $declarations = trim( $declarations );
190
191 if ( '' === $declarations ) {
192 return '';
193 }
194
195 // Check if declarations are already on multiple lines
196 if ( strpos( $declarations, "\n" ) !== false ) {
197 // Already formatted - preserve it
198 $lines = explode( "\n", $declarations );
199 $formatted_lines = array();
200
201 foreach ( $lines as $line ) {
202 $trimmed = trim( $line );
203
204 if ( '' !== $trimmed ) {
205 $formatted_lines[] = "\n\t" . $trimmed;
206 }
207 }
208
209 return implode( '', $formatted_lines ) . "\n";
210 }
211
212 // Single line - add minimal formatting
213 return ' ' . $declarations . ' ';
214 }
215
216 /**
217 * Find the matching brace in the CSS.
218 *
219 * @param string $css
220 * @param int $open_pos
221 *
222 * @return int
223 */
224 private function find_matching_brace( $css, $open_pos ) {
225 $level = 1;
226 $length = strlen( $css );
227 $in_string = false;
228 $string_char = '';
229
230 for ( $i = $open_pos + 1; $i < $length; $i++ ) {
231 $char = $css[ $i ];
232
233 // Handle string literals to avoid matching braces inside strings
234 if ( ( '"' === $char || "'" === $char ) && ( 0 === $i || '\\' !== $css[ $i - 1 ] ) ) {
235 if ( ! $in_string ) {
236 $in_string = true;
237 $string_char = $char;
238 } elseif ( $char === $string_char ) {
239 $in_string = false;
240 }
241 continue;
242 }
243
244 // Skip braces inside strings
245 if ( $in_string ) {
246 continue;
247 }
248
249 if ( '{' === $char ) {
250 ++$level;
251 } elseif ( '}' === $char ) {
252 --$level;
253
254 if ( 0 === $level ) {
255 return $i;
256 }
257 }
258 }//end for
259
260 return $length - 1;
261 }
262 }//end class
263