AngleSharp / AngleSharp.Css

:angel: Library to enable support for cascading stylesheets in AngleSharp.
https://anglesharp.github.io
MIT License
72 stars 34 forks source link

CssText property cuts off last semi-colon #60

Closed Displace99 closed 4 years ago

Displace99 commented 4 years ago

Bug Report

Prerequisites

Description

When using ComputeCurrentStyle() of an element and then calling the CssText property from it, the ending semi-colon is missing.

Steps to Reproduce

  1. Using default configuration
    IConfiguration config = Configuration.Default.WithDefaultLoader().WithCss();
    var _context = BrowsingContext.New(config);
  2. Using the following element as an example: <textarea id="txtTestArea" style="height:1in; width:6.5in;"></textarea>
  3. Use following code:
    var style = element.ComputeCurrentStyle();
    var styleText = style.CssText;

Expected behavior: I expect the variable styleText to have the value "display: inline-block; height: 1in; width: 6.5in;"

Actual behavior: [What actually happened] However the ending semi-colon is missing (from the width property) and results in "display: inline-block; height: 1in; width: 6.5in"

Environment details: [OS, .NET Runtime, ...] Operating System: Windows 10 Pro .Net Runtime: Core 3.1

Possible Solution

The only thing I was able to do is to manually add the semi-colon on to the end of the CssText property.

FlorianRappl commented 4 years ago

The serialization of a style is arbitrary (i.e., the use of semicolons, spaces, newlines, etc. can be chosen freely). A (trailing) semicolon is actually not enforced in CSS and can be omitted. If you want a different serialization then you can just provide your own (IStyleFormatter).

Keep in mind that you do not look at the original attribute - that value, of course, has the semicolon:

async Task Main()
{
    var config = Configuration.Default.WithDefaultLoader().WithCss();
    var context = BrowsingContext.New(config);
    var document = await context.OpenAsync(res => res.Content(@"<textarea style=""height:1in; width:6.5in;""></textarea>"));
    var textarea = document.QuerySelector("textarea");
    var originalAttribute = textarea.GetAttribute("style");
    var inlineStyle = textarea.GetStyle();
    var computedStyle = textarea.ComputeCurrentStyle();

    originalAttribute.Dump(); // height:1in; width:6.5in;
    inlineStyle.CssText.Dump(); // height: 1in; width: 6.5in
    computedStyle.CssText.Dump(); // display: inline-block; height: 1in; width: 6.5in
}

Hope that helps!

Displace99 commented 4 years ago

So this issue came up from another issue I was having.

I was trying to add the resize property to existing style using the setProperty("resize", "none");, but it didn't work. I couldn't find any documentation on how else to add it, so I went with what I felt was a hacky way and added the resize property to the end of the CssText and then reset the style attribute. And when I did that, I had to manually add the semi-colon.

FlorianRappl commented 4 years ago

The problem with SetProperty("resize", "none") was / is that AngleSharp does not know the resize declaration.

This could be an enhancement (https://developer.mozilla.org/en-US/docs/Web/CSS/resize).

Either way you can configure AngleSharp to allow it:

async Task Main()
{
    var config = Configuration.Default.WithDefaultLoader().WithCss(new CssParserOptions
    {
        IsIncludingUnknownDeclarations = true,
    });
    var context = BrowsingContext.New(config);
    var document = await context.OpenAsync(res => res.Content(@"<textarea style=""height:1in; width:6.5in;""></textarea>"));
    var textarea = document.QuerySelector("textarea");
    textarea.GetStyle().SetProperty("resize", "none");

    textarea.GetStyle().CssText.Dump(); // height: 1in; width: 6.5in; resize: none
    textarea.GetAttribute("style").Dump(); // height: 1in; width: 6.5in; resize: none
}

Hope that helps!

Displace99 commented 4 years ago

That works. Thanks!