CSSStyleSheet class disappears when parsing an SVG string - css

Example: JSFiddle
I have an svg image with a style element
<svg ...>
<style>
...
</style>
...
</svg>
If I embed the svg onto an empty HTML document, these two blocks of code result in a difference that I didn't expect.
block #1
let svg = document.querySelector("svg")
block #2
let s = new XMLSerializer();
let p = new DOMParser();
let svg = p.parseFromString(s.serializeToString(document.querySelector("svg")), "image/svg+xml").documentElement;
These two blocks produce a difference in regards to the <style> child (.children[0] here). The CSSStyleSheet is normally found on the "sheet" property on the <style> child:
svg.children[0].sheet
in block #1, the "sheet" property is available.
in block #2, it's null.
why is this? Am I doing something wrong in block #2? The <style> child exists in both cases, it just isn't recognized as a CSSStyleSheet in block #2.
The purpose of all of this is that I am building an SVG parser, so I need to be able to load files as strings and parse them.
workaround?: I can get the innerHTML of the <style> element in both cases, but CSSStyleSheet doesn't have a simple constructor where I can pass in the entire string; that would be nice, I could construct a new CSSStyleSheet. I can create a CSSStyleSheet and add rules individually, but I think I need to parse CSS, which sounds difficult.
I just want the benefit of the CSSRuleList. being able to iterate over that is super helpful.

I found the solution. it's not well documented
A <style> element must be a child of the HTMLDocument (not XMLDocument, nor parent-less) for the "sheet" property to exist and be of type CSSStyleSheet.
this was previously uncovered in this question.
solution (summary)
append the <style> element to the window.document.body, then access "sheet" property.
solution (detail)
get the root parent node of the <style> element (loop .parentNode until at root).
check the type of root with root.constructor === window.HTMLDocument.
(you can't test against null because XMLDocument will not generate a "sheet" property)
if #2 is true, "sheet" property will exist. if false, continue:
append the <style> to document.body. (or the <svg> if it contains the style. both work)
the sheet property now exists. do whatever you need with it.
remove <style> from document.body.

Related

How do I add the same CSS property (e.g. background-image) multiple times with React?

I want to do the equivalent of style="background-image: url(foo.jpg); background-image: -webkit-image-set(url(foo_1x.jpg) 1x, url(foo_2x.jpg) 2x)" in a React component.
React requires me to provide a style object, not a string. But a JS object can't have the same property twice.
How do I get two background-image properties? Also, the order is significant – the image-set needs to be last.
It needs to be an inline style. (Because the URL is a dynamic, interpolated value retrieved from DB.)
I think I initially misunderstood your question. Seems you are looking to create a style object to pass as a prop to a component. You can combine your background images into a single comma separated list. You can use a string template to inject the dynamic image urls at runtime.
const style = {
backgroundImage: `url(${url1}),-webkit-image-set(url(${url2}) 1x, url(${url3}) 2x)`,
};
"spassvogel" on GitHub has a clever solution using CSS variables: https://github.com/facebook/react/issues/20757#issuecomment-776191029
The idea is to set CSS variables in the style property, like
style={ "--url1": "url(1.jpg)", "--url2": "url(2.jpg)" }
and then using them from an external style sheet, like
background-image: var(--url1);
and so on.
Turns out this still wasn't enough to solve everything I wanted – this rabbit hole runs ever deeper – but that's no fault of React's, so I'll consider this a valid answer.

AngleSharp Css Query For Element Style Using Path

Given only a css stylesheet, is it possible to parse and query the stylesheet using some sort of a path query to retrieve a computed style similar to what is returned from IElement.ComputeCurrentStyle()?
var css = #"
<style>
table { font-family:foobar }
td { font-weight:bold }
</style>
";
var config = Configuration.Default.WithDefaultLoader().WithCss();
var context = BrowsingContext.New(config);
IDocument document = await context.OpenAsync(req => req.Content(css));
ICssStyleSheet sheet = document.GetStyleSheets().OfType<ICssStyleSheet>().First()
Is it possible to do something like sheet.GetComputedStyle("body>table>tbody>tr>td") to retrieve a ICssStyleDeclaration?
Got a response to this on the github project issue tracker
https://github.com/AngleSharp/AngleSharp.Css/issues/64
Well to get a computed style you need to have a connection to the DOM. After all, things like selectors can only be computed in context of an available DOM structure.
I guess what you are after is to "fake" the DOM, i.e., if you see some selector (like body>table>tbody>tr>td) create the minimal DOM to be able to get an element that satisfies the selector. Then use this element to get the computed style, right?
Out of the box this is not possible, but I think it should be doable to write this.

Specify an element display as image

For example i have a DTD
DTD:
<!ELEMENT tbl EMPTY>
<!ATTLIST tbl tableWidth CDATA "0">
<!ELEMENT MyImage EMPTY>
<!ATTLIST MyImage source CDATA "sample.png">
Valid XML:
<tbl tableWidth ="100" />
<MyImage source="image.png"/>
Now in CSS for element tbl I can specify it as
tbl {
display: table;
}
This means that element tbl should be displayed as table. But if we want to display MyImage element as image how can we do that?
Image should come from source attribute. As there is no image value for display css property.
In CSS, an image is a replaced element,
An element whose content is outside the scope of the CSS formatting model, such as an image, embedded document, or applet.
This means CSS doesn't define how replaced content is rendered. It's left entirely to the user agent. And this is why there is no display: image value.
If only browsers implemented CSS3's attr(), you could cheat by doing something like this (which actually results in a replaced pseudo-element):
MyImage::before {
content: attr(source url);
}
But since no browser still implements it as of today, you're pretty much stuck. (Technically the supposed way to do this is to implement a custom user agent for your XML, but I'm not sure most authors are prepared for that.)

Is there any way to check an inherited CSS property in protractor?

I am writing some protractor tests for an Angular app.
After blurring an input field, a CSS file is reloaded in the application, and I'd like to test if that style has effectively being applied to the elements that uses classes from that CSS file.
I've seen I can read values that are effectively on the styles attribute.
If it is not possible, then is there any way to test some element is rendered correctly using protractor??
element.all(by.css('.input')).get(0).then(function(styleProperty){
styleProperty.clear();
styleProperty.sendKeys('10px', protractor.Key.TAB);
element(by.css('.element')).getCssValue('border').then(function (borderCssValue) {
expect(borderCssValue).toBe('10px');
});
Message:
Expected '' to be '10px'.
border is not a valid css value, since it expands to border-top, border-left, etc. Try
element(by.css('.element')).getCssValue('border-top').then(...)

Oracle Apex control CSS layout for Standard Report Columns

I have an ApEx report where i need to customize the css width of columns differently. For this I'm using the CSS Class attribute in the report:
The CSS Class assigned is as shown: WideColumn
And in the HTML header for the application page :
<style type="text/css">
.WideColumn {
min-width:100px;
}
</style>
This is not taking effect. In fact whatever css attributes are assigned, do not take effect.
I do not want to use the CSS Style section to specify 'display:block;min-width:100px;' due to certain limitations.
What is it that I'm missing out in the column attributes?
I've tried CSS Class within quotes too: 'WideColumn' Please suggest.
The custom row template can not deal with the CSS class definition. The CSS under "Column formatting" normally generates a span element with a class set to it, not the td element. Setting the "Element CSS class" for the element itself will not always help aswell. If your column type is a "Standard Report Column" then no extra html is created.
You also have no option of providing a substitution string in the template itself to create some output.
You could
add an extra column in the source query which will contain a class.
Use the column header in the row template to add this custom class.
alternatively use the class column in the html expression of the
column you want to change. Similar to standard output, you could use
<span class="#CLASSCOL#">#MYCOL#</span> to generate that html.
target the generated column with CSS. For instance, if your template
generates th elements and a headers attribute on td elements
(like in standard reports), you can target those columns much more
easily than fiddling with classes or html expressions. You might need
to adapt the template but it should be generally beneficial.
You can do this with some Javascript using the jQuery library built into APEX.
(WARNING: My Javascript isn't the world's most elegant!)
This worked for me:
1) In the "Function and Global Variable Declaration" attribute of the page create this function:
function setColWidths(colId) {
var maxWidth = 0;
$('th#'+colId).each (function (index) {
w = $(this).width();
maxWidth = Math.max(maxWidth,w);
});
$('th#'+colId).each (function (index) {
$(this).width(maxWidth);
});
}
2) In the "Execute when Page Loads" attribute of the page call the function for each column:
setColWidths('COL01');
setColWidths('COL02');
setColWidths('COL03');

Resources