-
Notifications
You must be signed in to change notification settings - Fork 186
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
Refactor specificity #59
Conversation
Don't use a value, but compare the 3 values in a seperate class. And don't add the order to the specificity, only use it when the specificity is equal.
I think this will be no longer an issue, as the class uses XPath instead of regexes |
Yes it is, this has nothing to do with each other. |
Oeps, my mistake, must have missed the point. |
This is an alternative to tijsverkoyen#59 The patch in tijsverkoyen#59 is better, but this illustrates the problem better. The order shouldn't have any effect on the specificity, it should only count when the specificity is the same..
I used the basic example from: http://zurb.com/ink/downloads/templates/sidebar-hero.html (source zip) The specificity fails on Click me block, probably because you add the $i to each specificity, so when the first element is 1, the 100th is 101, while it only has a specificity of 1.. |
And for the change in Specificity, I don't have any example that goes wrong, but see this issue for a discussion: symfony/symfony#11400 You can't just compare specificity values like this, but it still works, as long as you don't have more then 10 classes/id's/parts. But comparing it like this should work no matter what. |
Conflicts: CssToInlineStyles.php
// return | ||
return $specificity; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tjhink this logic does not work properly for #id.class1.class2::hover
for instance. And it also break for [data-type="foo bar"]
.
In the first case, it will set it to 1, 0, 0
instead of 1, 2, 1
. In the second case, it will set it to 0, 0, 2
instead of 0, 1, 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, but that was also the case earlier.
We could bring in the Selector Parse from the CssSelector component, if that's not a bit overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we can only use the compare method from the Specificity class when Symfony 2.6 is released, so we would have to use the value (shouldn't be too big a problem, but neither are perfect)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already thought about getting the specificity from the Symfony parser. I haven't yet tried how much refactoring it would involve in the library (it would not be doable when using CssSelector::toXPath
static method as this one does not give you the parsed selector at all btw).
and bumping the dependency to 2.6+ would also be an issue, because it would make the library unusable in Symfony <2.6 projects. If we use the value, we would face the same bug when you have big selectors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
however, the first fix is indeed to separate the specificity and the order handling for the comparison, which is making the bug much more likely to happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe counting the occurrences of the #
and .
in a string, as starters?
foreach ($chunks as $chunk) {
$first = substr($chunk, 0, 1);
$a = substr_count($chunk, '#');
$b = substr_count($chunk, '.');
$c = ($first !== '.' && $first !== '#') ? 1 : 0;
$specificity->increase($a,$b,$c);
}
I'm not very good at regexes, otherwise that might be an idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And perhaps better just merge this PR and then create a new issue to focus on getting the actual correct specificity? What do you think @tijsverkoyen ?
And added getValues() (for easier testing) and changed to compareTo, in line with the CssSelector component.
I changed the calculation of the specificity to match that of the css_parser from premailer, which should have pretty good results, except for a few edge cases.
The 2 cases from @stof has the first one different then he said in his example, but I think the output from the regex is correct (the hover counts as b factor, not c).
|
Good patch, this sorted many problems with my emails built on Zurb Ink templates. What it didn't sort was the following cascade:
When inlined, the CSS styles for |
You are on version 1.4.1, right? Didn't this PR solve that? #58 When the unit tests PR is merged, it would be easier to test for these edge cases and avoid problems.. |
Yes, I'm on 1.4.1 with #58 merged, and the above |
Can you check with #62 ? |
Don't use a value, but compare the 3 values in a seperate class. And don't add the order to the specificity, only use it when the specificity is equal. This will prevent cases where the specificity is increased too much because many rules. This replaces #56
This is following the spec better, so that 2,0,1 > 1,12,1 (vs 201 < 221, which is incorrect)
/cc @stof What do you think, something like this compare also for the CssSelector component?