AngleSharp Css Query For Element Style Using Path - anglesharp

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.

Related

CSSStyleSheet class disappears when parsing an SVG string

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.

Is there a way to forcefully find a CSS selector element/bring it into view?

Let's say for example I'm going through my stylesheet but I can't remember what element a certain CSS selector affects.
Is there any method, tool, or anything that I could do/use to find out what exactly it is affecting?
Thanks!
I just opened up a random bootstrap template site and did what you where asking for.
Open up your chrome browser (I prefer this as I feel this is easy to debug both Jquery and css) and Press F12, you will get a developer window as in the image.
Switch to the console tab.
Use Jquery selector to select all
the intended elements (you can use the same css selector here too
but just place them inside $('')) Eg: $('.tab-content') I am trying to find out all the elements with the class tab-content
The result is all the elements
of that selector.
NOTE: This appraoch woud require you to have Jquery loaded into your page. Else the script will throw an error saying $ is not defind.
In addition to using your browser's development tools, there are two easy ways to do it that should work in almost any browser (no matter how bad the developer environment).
Visually
Temporarily set a border or background color for the selector, like:
border: 1px solid red;
Or:
background: red;
This makes it very easy to find the affected elements.
Programmatically
On the JavaScript console, use:
// Replace with something that prints the relevant details
var stringify = function(element) { return element.innerHTML; };
// Iterate over all affected elements and print relevant info
var affectedElements = document.querySelectorAll('.your .selector');
var len = affectedElements.length;
console.log('Elements affected: ' + len);
for (var i = 0; i < len; i++) {
var affectedElement = affectedElements[i];
console.log(
'Element ' + (i+1) + ':\n' +
stringify(affectedElement) + '\n\n');
}
The inspection of elements feature of the browser is meant for the purpose you want.
1.Open up the index file in any browser(preferably Mozilla Developer edition),
2.Right click and Inspect element,
3.Then open the compiled stylesheet. Find out the style element you want to check the effect of.
4. Go back to inspection, remove/add CSS properties and see the effect in real time.
The other way is to use Adobe brackets. It's live preview feature will highlight the section that involves the code snippet, you point your cursor to.

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');

Is it possible to create a new css property?

Is it possible to create a new property in CSS? For example, say you're developing a control that displays a photo and you want to add a property to css to control what style frame to have around the photo. Something like:
#myphoto { frame-style: fancy }
Is there some way to do this in a cross browser compatible manner, and how would you define whether the style inherits or not?
EDIT: It's a custom control - your JS code would deal with the style - I'm not expecting the browser to magically know what to do. I want the user to be able to style the control with CSS instead of JS.
Sure, why not. Check this out as an example: http://bililite.com/blog/2009/01/16/jquery-css-parser/
You may also be able to get away with using CSS classes instead of properties. Not sure if that works for what you're doing.
You can't. Browsers interpret CSS based on how their layout engines are coded to do so.
Unless you took an existing open source engine like WebKit or Gecko, added custom code to handle your custom CSS and made a browser that used your customized layout engine. But then only your implementation would understand your custom CSS.
Re your edit: it'd depend on whether you're able to read that style somehow. Typically browsers just instantly discard any properties they don't recognize, and CSS is not normally reachable by JavaScript because CSS code is not part of the DOM.
Or you could look at Jordan's answer.
If you'd prefer a straight JavaScript solution that uses no JS libraries, you could use the query string of a background-image to keep "custom properties" inside your CSS.
HTML
<div id="foo">hello</div>
CSS
#foo {
background: url('images/spacer.gif?bar=411');
}
JavaScript
getCustomCSSProperty('foo', 'bar');
Supporting JavaScript Functions
function getCustomCSSProperty(elId, propName)
{
var obj = document.getElementById(elId);
var bi = obj.currentStyle ? obj.currentStyle.backgroundImage : document.defaultView.getComputedStyle(obj, null).getPropertyValue('background-image');
var biurl = RegExp('url\\(["\\\']?([^"\\\']+)["\\\']?\\)').exec(bi);
return getParameterByName(propName, biurl[1]);
}
function getParameterByName(name, qs) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(qs);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
Demo:
http://jsfiddle.net/t2DYk/1/
Explanation:
http://refactorer.blogspot.com/2011/08/faking-custom-css-properties.html
I've tested the solution in IE 5.5-9, Chrome, Firefox, Opera, and Safari.

Applying style using javascript doesn't work always

I am applying style to div using JavaScript it appears well at the first time but when I click an image to open a virtual window the applied CSS goes away.
How can I apply style using script that stays forever.
**There is no way left for me to apply any style at design time because I am using ready made user control and I get ID for the DIV only at run time.
Any Idea??
Here is the script I am using...
window.onload = changeDivOverflow;
function changeDivOverflow()
{
var treeDiv = document.getElementById('T_ctl00contentMainctl04tvw');
treeDiv.style.overflow = "auto";
}
Since you are using ASP.NET, but I cannot see all your full code, I can only assume that your DIV has a runat="server" tag and that's why you cannot get the ID on the client side.
If this is the case, you may consider the following change to get the treeDiv:
var treeDiv = document.getElementById("<%= tvw.ClientID %>");
All styles you apply using javascript and DOM calls, apply only to element you are applying it. In your example it will be only element with ID = 'T_ctl00contentMainctl04tvw'
If you want to reuse that style for more than one element, you should create a CSS class and store that style there. Then apply that class for every element you want. If you want to do it with script, then you should:
var treeDiv = document.getElementById('T_ctl00contentMainctl04tvw');
treeDiv.className = "your-class";

Resources