-
Notifications
You must be signed in to change notification settings - Fork 41
style custom css option #2600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
style custom css option #2600
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
bc54c69
style custom css option
Liviu-p a611e06
merge master
Liviu-p aa4e30f
Merge branch 'master' into feature/ff-style-custom-css
Crabcyborg 237aa59
code cleanup, fix failing analysis
Liviu-p 3f5b9f4
Merge branch 'feature/ff-style-custom-css' of github.com:Strategy11/f…
Liviu-p 91d3a66
master merge conflict fix
Liviu-p 7d0710c
Merge branch 'master' into feature/ff-style-custom-css
Crabcyborg 93baf14
eslint fixes and phpcs
Liviu-p 55dc1b8
Merge branch 'feature/ff-style-custom-css' of github.com:Strategy11/f…
Liviu-p 12b7f5e
phpcs fix
Liviu-p 6c921e2
add unit tests for FrmCssScopeHelper
Liviu-p 65ef3c8
master merge conflicts fix
Liviu-p be7fca7
fix white spaces
Liviu-p 0180ddd
phpcs fixes
Liviu-p cf14703
remove white space before comment
Liviu-p 46aa3f6
Merge branch 'master' into feature/ff-style-custom-css
Crabcyborg eb4bcf1
Merge branch 'master' into feature/ff-style-custom-css
Crabcyborg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,262 @@ | ||
| <?php | ||
| if ( ! defined( 'ABSPATH' ) ) { | ||
| die( 'You are not allowed to call this page directly.' ); | ||
| } | ||
|
|
||
| class FrmCssScopeHelper { | ||
|
|
||
| /** | ||
| * Nest the CSS. | ||
| * This function nests the CSS by adding the class name prefix to the selectors. | ||
| * | ||
| * @param string $css | ||
| * @param string $class_name | ||
| * | ||
| * @return string | ||
|
Liviu-p marked this conversation as resolved.
|
||
| */ | ||
| public function nest( $css, $class_name ) { | ||
|
Crabcyborg marked this conversation as resolved.
|
||
| // Remove CSS comments but preserve newlines | ||
| $css = preg_replace( '/\/\*.*?\*\//s', '', $css ); | ||
|
|
||
| $output = array(); | ||
| $css = trim( $css ); | ||
| $length = strlen( $css ); | ||
| $i = 0; | ||
| $buffer = ''; | ||
|
|
||
| while ( $i < $length ) { | ||
| $char = $css[ $i ]; | ||
|
|
||
| if ( '@' === $char ) { | ||
| $brace_pos = strpos( $css, '{', $i ); | ||
|
|
||
| if ( false === $brace_pos ) { | ||
| $buffer .= $char; | ||
| ++$i; | ||
| continue; | ||
| } | ||
|
|
||
| $rule = substr( $css, $i, $brace_pos - $i ); | ||
| $closing_brace = $this->find_matching_brace( $css, $brace_pos ); | ||
| $inner_content = substr( $css, $brace_pos + 1, $closing_brace - $brace_pos - 1 ); | ||
|
|
||
| // Don't nest keyframes content | ||
| if ( strpos( $rule, '@keyframes' ) !== false ) { | ||
| $output[] = "\n" . $rule . ' {' . $inner_content . '}' . "\n"; | ||
| } else { | ||
| $output[] = "\n" . $rule . ' {'; | ||
| $output[] = $this->nest( $inner_content, $class_name ); | ||
| $output[] = '}' . "\n"; | ||
| } | ||
|
Liviu-p marked this conversation as resolved.
|
||
|
|
||
| $i = $closing_brace + 1; | ||
| $buffer = ''; | ||
| continue; | ||
| }//end if | ||
|
Crabcyborg marked this conversation as resolved.
Liviu-p marked this conversation as resolved.
|
||
|
|
||
| if ( '{' === $char ) { | ||
| $selector = trim( $buffer ); | ||
| $closing_brace = $this->find_matching_brace( $css, $i ); | ||
| $declarations = substr( $css, $i + 1, $closing_brace - $i - 1 ); | ||
|
|
||
| // Preserve indentation and formatting of declarations | ||
| $declarations = $this->preserve_declaration_formatting( $declarations ); | ||
|
|
||
| if ( '' !== $selector && '' !== trim( $declarations ) ) { | ||
| // Handle multiple selectors | ||
| $selectors = array_map( 'trim', explode( ',', $selector ) ); | ||
| $prefixed_selectors = array(); | ||
|
|
||
| foreach ( $selectors as $single_selector ) { | ||
| if ( '' !== $single_selector ) { | ||
| $prefixed_selectors[] = '.' . $class_name . ' ' . $single_selector; | ||
| } | ||
| } | ||
|
|
||
| if ( ! empty( $prefixed_selectors ) ) { | ||
| $output[] = "\n" . implode( ',' . "\n", $prefixed_selectors ) . ' {' . $declarations . '}' . "\n"; | ||
| } | ||
| } | ||
|
|
||
| $i = $closing_brace + 1; | ||
| $buffer = ''; | ||
| continue; | ||
| }//end if | ||
|
|
||
| $buffer .= $char; | ||
| ++$i; | ||
| }//end while | ||
|
|
||
| return implode( '', $output ); | ||
| } | ||
|
|
||
| /** | ||
| * Unnest the CSS. | ||
| * This function unnests the CSS by removing the class name prefix from the selectors. | ||
| * | ||
| * @param string $css | ||
| * @param string $class_name | ||
| * | ||
| * @return string | ||
| */ | ||
| public function unnest( $css, $class_name ) { | ||
| // Remove CSS comments but preserve newlines | ||
| $css = preg_replace( '/\/\*.*?\*\//s', '', $css ); | ||
|
|
||
| $output = array(); | ||
| $css = trim( $css ); | ||
| $length = strlen( $css ); | ||
| $i = 0; | ||
| $buffer = ''; | ||
| $prefix = '.' . $class_name . ' '; | ||
| $prefix_length = strlen( $prefix ); | ||
|
|
||
| while ( $i < $length ) { | ||
| $char = $css[ $i ]; | ||
|
|
||
| if ( '@' === $char ) { | ||
| $brace_pos = strpos( $css, '{', $i ); | ||
|
|
||
| if ( false === $brace_pos ) { | ||
| $buffer .= $char; | ||
| ++$i; | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| $rule = substr( $css, $i, $brace_pos - $i ); | ||
| $closing_brace = $this->find_matching_brace( $css, $brace_pos ); | ||
| $inner_content = substr( $css, $brace_pos + 1, $closing_brace - $brace_pos - 1 ); | ||
|
|
||
| $output[] = "\n" . $rule . ' {'; | ||
| $output[] = $this->unnest( $inner_content, $class_name ); | ||
| $output[] = '}' . "\n"; | ||
|
|
||
| $i = $closing_brace + 1; | ||
| $buffer = ''; | ||
| continue; | ||
| }//end if | ||
|
|
||
| if ( '{' === $char ) { | ||
| $selector = trim( $buffer ); | ||
| $closing_brace = $this->find_matching_brace( $css, $i ); | ||
| $declarations = substr( $css, $i + 1, $closing_brace - $i - 1 ); | ||
|
|
||
| // Preserve indentation and formatting of declarations | ||
| $declarations = $this->preserve_declaration_formatting( $declarations ); | ||
|
|
||
| if ( '' !== $selector && '' !== trim( $declarations ) ) { | ||
| // Handle multiple selectors | ||
| $selectors = array_filter( | ||
| array_map( 'trim', explode( ',', $selector ) ), | ||
| function ( $s ) { | ||
| return '' !== $s; | ||
| } | ||
| ); | ||
| $unprefixed_selectors = array(); | ||
|
|
||
| foreach ( $selectors as $single_selector ) { | ||
| $unprefixed_selectors[] = 0 === strpos( $single_selector, $prefix ) | ||
| ? trim( substr( $single_selector, $prefix_length ) ) | ||
| : $single_selector; | ||
| } | ||
|
|
||
| if ( ! empty( $unprefixed_selectors ) ) { | ||
| $output[] = "\n" . implode( ',' . "\n", $unprefixed_selectors ) . ' {' . $declarations . '}' . "\n"; | ||
| } | ||
| } | ||
|
|
||
| $i = $closing_brace + 1; | ||
| $buffer = ''; | ||
| continue; | ||
| }//end if | ||
|
|
||
| $buffer .= $char; | ||
| ++$i; | ||
| }//end while | ||
| return implode( '', $output ); | ||
| } | ||
|
|
||
| /** | ||
| * Preserve declaration formatting with proper indentation. | ||
| * | ||
| * @param string $declarations | ||
| * | ||
| * @return string | ||
| */ | ||
| private function preserve_declaration_formatting( $declarations ) { | ||
| // Trim the entire block but keep internal structure | ||
| $declarations = trim( $declarations ); | ||
|
|
||
| if ( '' === $declarations ) { | ||
| return ''; | ||
| } | ||
|
|
||
| // Check if declarations are already on multiple lines | ||
| if ( strpos( $declarations, "\n" ) !== false ) { | ||
| // Already formatted - preserve it | ||
| $lines = explode( "\n", $declarations ); | ||
| $formatted_lines = array(); | ||
|
|
||
| foreach ( $lines as $line ) { | ||
| $trimmed = trim( $line ); | ||
|
|
||
| if ( '' !== $trimmed ) { | ||
| $formatted_lines[] = "\n\t" . $trimmed; | ||
| } | ||
| } | ||
|
|
||
| return implode( '', $formatted_lines ) . "\n"; | ||
| } | ||
|
|
||
| // Single line - add minimal formatting | ||
| return ' ' . $declarations . ' '; | ||
| } | ||
|
|
||
| /** | ||
| * Find the matching brace in the CSS. | ||
| * | ||
| * @param string $css | ||
| * @param int $open_pos | ||
| * | ||
| * @return int | ||
| */ | ||
| private function find_matching_brace( $css, $open_pos ) { | ||
| $level = 1; | ||
| $length = strlen( $css ); | ||
| $in_string = false; | ||
| $string_char = ''; | ||
|
|
||
| for ( $i = $open_pos + 1; $i < $length; $i++ ) { | ||
| $char = $css[ $i ]; | ||
|
|
||
| // Handle string literals to avoid matching braces inside strings | ||
| if ( ( '"' === $char || "'" === $char ) && ( 0 === $i || '\\' !== $css[ $i - 1 ] ) ) { | ||
| if ( ! $in_string ) { | ||
| $in_string = true; | ||
| $string_char = $char; | ||
| } elseif ( $char === $string_char ) { | ||
| $in_string = false; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| // Skip braces inside strings | ||
| if ( $in_string ) { | ||
| continue; | ||
| } | ||
|
|
||
| if ( '{' === $char ) { | ||
| ++$level; | ||
| } elseif ( '}' === $char ) { | ||
| --$level; | ||
|
|
||
| if ( 0 === $level ) { | ||
| return $i; | ||
| } | ||
| } | ||
| }//end for | ||
|
|
||
| return $length - 1; | ||
| } | ||
| }//end class | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.