Styling content inserted in the Shadow DOM - javascript

I have this example:
http://codepen.io/dbugger/pen/IuDxw
Where I have an insertion point inside the Shadow DOM and I try to apply an style to it, making it disappear. But the image is still visible. I suspect there is some principle I haven't undestood propely from the Web Components.
Can someone explain me what am I doing wrong?

The trick is that the image is not, as kkemple mentioned, part of the Shadow DOM, but rather the Light DOM, which means it's not directly accessible from inside the component. It's user provided content, like the parameters passed into a class constructor in an OOP language. If at all possible, then, the user should provide their own styles to go with it.
That being said, there are definitely valid use cases where the component author wants to style user-provided content. Hiding certain parts of the user-provided markup based on attributes on the host, events (clicks), etc. is definitely one of those. In that case, wrap the <content> element in a Shadow DOM element and hide that:
<template>
<style>
.image {
display: none;
}
</style>
<div class="image">
<content></content>
</div>
</template>
http://codepen.io/anon/pen/rCGqD
On a side note: It is technically possible to apply styles directly to Light DOM elements, but be aware that in many cases this is considered leaking implementation details to the outside world. If the first solution works, use that instead.

It is not working is because your code is not in the shadow DOM, the div and image is still accessible through default styling. I forked your codepen and added the styling so you could see.
var host = document.querySelector(".host");
var template = document.getElementById( 'template' );
var root = host.webkitCreateShadowRoot();
root.appendChild( template.content );
<template id="template">
<style>
.wrapper {
display: none;
}
</style>
<div class="wrapper">
<content selector=".img"></content>
</div>
<h2>In the Shadows</h2>
</template>
<style>
img {
border: 1px solid black;
}
</style>
<div class="host">
<img class="img" src="http://placehold.it/200x275&text=1" alt="" />
</div>
http://codepen.io/kkemple/pen/euBKs
I didn't go in to why it was not creating a shadow DOM element as your JS looked correct to me but here is a great article on shadow DOM web-ponents:
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/

Related

How to dynamically generate CSS rules in Blazor

In other words, I need to generate css classes and inject them somehow into the page.
I need to modify the classes at runtime in C#.
Why?
Let's say my razor component renders thousands of elements and I need to change width of all those elements.
Rather than modifying style attribute on many elements I would like to just modify single css rule.
JS interop is acceptable.
First, avoid placing style tags inside components. Each time the component is rendered, so is the style tag. In addition, it makes it difficult for other developers to find your CSS if it is scattered all over the app in components.
I don't normally suggest using inline styles, but CSS variables have really changed my outlook on this. CSS property variables allow you to dynamically pass values to your CSS at runtime using the style attribute.
#* This belongs in app.css *#
<style>
:root {
--my-width: 100px;
}
.example {
background-color: #ccc;
width: var(--my-width);
}
</style>
#* ^ This belongs in app.css *#
<h1>Hello, Blazor REPL!</h1>
<label>Width</label>
<input #bind-value="#width" />
<p class="example" style="--my-width: #width">My Width is #width</p>
#code {
string width = "100px" ;
}
You can see an example of this running in the browser here. https://blazorrepl.com/repl/cFOdkmPA10gU73Hl18
I had a similar thing I needed to edit in Blazor. Long story short is MatBlazor Tabs adds a style="pointer-events: auto;" that I needed to disable when loading data.
https://www.matblazor.com/Tab
I solved it like this:
index.html:
window.ChangeMatBlazorTabPointerEvents = (loadData) => {
var allTabs = document.querySelectorAll('.mdc-tab__content');
allTabs.forEach((tab) => {
if (loadData) {
tab.style.pointerEvents = 'none';
}
else {
tab.style.pointerEvents = 'auto';
}
});
}
Blazor (razor) file::
#inject IJSRuntime JSRuntime
await JSRuntime.InvokeVoidAsync("ChangeMatBlazorTabPointerEvents", loadData);
Example why I had to do it:
<MatTab Label="Threats and Countermeasures" Style="pointer-events: inherit;">
Renders this:
<div class="matBlazor_theme_12345678-1234-1234-1234-123456789012 mat-tab-label mdc-tab" style="pointer-events: inherit;" role="tab" tabindex="0" id="matBlazor_id_82bcf7fc-5f04-48a0-aff0-d24dcc0b0ac3" _bl_92=""><!--!-->
<span class="mdc-tab__content" style="pointer-events: auto;"><!--!-->
<span class="mdc-tab__text-label">Threats and Countermeasures</span><!--!-->
</span><!--!-->
<span class="mdc-tab-indicator "><!--!-->
<span class="mdc-tab-indicator__content mdc-tab-indicator__content--underline"></span>
</span><!--!-->
<span class="mdc-tab__ripple"></span>
</div>
Does not currently work due to <span class="mdc-tab__content" style="pointer-events: auto;">
The following code does not work either since the tab will still have style="pointer-events: auto;"
<MatTab>
<LabelContent>
<span style="#((loadData ? "pointer-events: none;" : ""))"> Threats and Countermeasures </span>
</LabelContent>
<ChildContent>
Content
</ChildContent>
</MatTab>

Use of Pseudo-Elements in Polymer.js

I'm taking my first steps with Polymer.js, and I'm struggling with creating a pseudo-element.
This is what I tried:
In my host document:
<style type="text/css">
#host::x-a-cool-test {
color: green;
}
</style>
<div id="host">
<my-custom-element></my-custom-element>
</div>
In my custom element:
<element name="my-custom-element">
<template>
<style>
#host {
* { display: block; color: blue; }
}
</style>
<div id="group" pseudo="x-a-cool-test">
just some text
</div>
</template>
<script>
Polymer.register(this);
</script>
</element>
That will show just my text in blue. That is correct, because according to this, rules wrapped in a #host have higher specificity than any selector in the parent page.
My question:
If I delete color: blue from inside the #host block in my template, the text is shown in black and NOT green as I would expect. Why is that???
I believe this plunker works how you want it to. Basically, the CSS pseudo-element has to be applied directly to the custom element (in this case the my-custom-element). I switched id="host" to it (instead of its parent div) and the code worked.
<div>
<my-custom-element id="host"></my-custom-element>
</div>
Note: The overriding nature of #host may change. Some (myself included) think it should be more for providing default, fallback styles. In this case rules in the host document will override #host rules instead of the other way around.

Javascript output won't accept any CSS styling

I'm using simplecart.js which generates data for me to add to a cart, and then passes it to PayPal for me.
I have successfully added the 'add to basket' and 'checkout' features but am finding styling the JS-generated code impossible as no styles applied to it will work.
This is the code site has given to me, which generates a number of items such as name, quantity etc from stored data. It outputs all information correctly but any styles applied to the class names do nothing.
This is the code that generates the data:
<div class="simpleCart_items"></div>
This is the result from the web browser:
<div class="simpleCart_items"><div>
<div class="headerRow">
<div class="item-name">Name</div>
<div class="item-price">Price</div>
<div class="item-quantity">Qty</div>
<div class="item-remove"></div>
</div>
<div class="itemRow row-0 odd" id="cartItem_SCI-3">
<div class="item-name">The Jenny Snood £11</div>
<div class="item-price">£11.00</div>
<div class="item-quantity">1</div>
<div class="item-remove">
Remove
</div>
</div>
</div>
</div>
The browser is receiving all the data correctly, but applying any styles to the class names does nothing. For example, I have:
.headerRow{
background-colour:#0F0;
}
The result should be that the background of headerRow be lime, but nothing happens. It is not calling the style correctly.
I have tried everything but none of the classes will fetch the styles applied to them.
Here is a screenshot of how it looks, obviously not very nice unstyled, but I can't apply any styles at all to it.
Here is a link to the live site
A further examples:
I've added the code given which generates the totals:
<div class="simpleCart_total"></div>
I have tried giving it it's own new class and also styling the original, with !important - none of this works.
<div class="totals simpleCart_total"></div>
.simpleCart_total{
background-color:#0F0 !important;
}
.totals{
background-color:#0F0 !important;
}
None of the above seems to have any impact whatsoever.
There is some other css or inline javascript affecting the custom style your are attempting to use.
To mitigate this issue do one of the following:
Add !important after each css statement like so:
.headerRow{background-color:#0F0 !important;}
Reorder the css files so your custom css file is at the bottom
The problem here is that the styles are being applied dynamically by the js after your CSS (ie during the initialization of the plugin). You're only hope is to style it after this initialization with your own js, I think.
You can check this in Firebug... If you look at the elements there, you should see a bunch of inline styles being applied to them. These will trump your CSS in the header (and even the inline CSS you provide beforehand).
Edit: I saw some junky characters just before the directives in question (as well as those pointed out in another answer). I would try removing all the white space after the preceding directive and before the broken ones. It does not appear that the js is dynamically changing anything.

Wrap link <a> around <div>

Is it possible to wrap an <a> tag around <div>s like so:
<a href=etc etc>
<div class="layout">
<div class="title">
Video Type
<div class="description">Video description</div>
</div>
</div>
</a>
Eclipse is telling me the div's are in the wrong place?
If this is not allowed. How can I make the entire 'layout' class become a link?
That structure would be valid in HTML5 since in HTML5 anchors can wrap almost any element except for other anchors and form controls. Most browsers nowadays have support for this and will parse the code in the question as valid HTML. The answer below was written in 2011, and may be useful if you're supporting legacy browsers (*cough* Internet Explorer *cough*).
Older browsers without HTML5 parsers (like, say, Firefox 3.6) will still get confused over that, and possibly mess up the DOM structure.
Three options for HTML4 - use all inline elements:
<a href=etc etc>
<span class="layout">
<span class="title">
Video Type
<span class="description">Video description</span>
</span>
</span>
</a>
Then style with display: block
Use JavaScript and :hover:
<div class="layout">
<div class="title">
Video Type
<div class="description">Video description</div>
</div>
</div>
And (assuming jQuery)
$('.layout').click(function(){
// Do something
}):
And
.layout:hover {
// Hover effect
}
Or lastly use absolute positioning to place an a anchor with CSS to cover the whole of .layout
<div class="layout">
<div class="title">
Video Type
<div class="description">Video description</div>
</div>
<a class="more_link" href="somewhere">More information</a>
</div>
And CSS:
.layout {
position: relative;
}
.layout .more_link {
position: absolute;
display: block;
top: 0;
bottom: 0;
left: 0;
right: 0;
text-indent: -9999px;
z-index: 1000;
}
This won't work with older versions of IE, of course.
While the <a> tag is not allowed to contain <div> element, it is allowed to contain other inline elements such as <span>.
When I encountered the problem i swapped the div tag with a <span>. Since the span tag is an inline element, you need to apply a display:block to the css of your <span> element, in order to make it behave like the <div> block element.
This should be valid xhtml and does not require any javascript.
Here's an example:
<a href="#">
<span style="display:block">
Some content. Maybe some other span elements, or images.
</span>
</a>
Another simple solution - just add an onclick event handler to the div thusly:
<div class="layout" onclick="location.href='somewhere'">
<div class="title">
Video Type
<div class="description">Video description</div>
</div>
</div>
This works great for me but there is one small gotcha. I'm not sure how search engine friendly this is. I fear that google's web crawlers might not find this link so I also tend to include a traditional A HREF link somewhere in the block like this:
<div class="layout" onclick="location.href='destination_url'">
<div class="title">
Video Type
<div class="description">Video description</div>
</div>
This is a link
</div>
Timothy's solution is correct ... instead of wrapping an anchor around a div ... you simply give layout to the anchor element with display:block and add the size and width of the anchor ...
.div_class { width: 100px; height: 100px; }
.div_class a { width: 100px; height: 100px; display: block; }
<div class='div_class'></div>
HTML provides two general elements, where div is a natural block element, and span is a natural inline element. All other elements are similarly assigned to be a natural block or inline.
Now, while both can be made by css display to be any of inline, inline-block or block, they are still treated for enclosure purposes as their natural selves, hence the warning messages. Leopards and spots sort of thing.
However, css is only meant to be for making what an element looks like (presentation), but not actually be like (functionality), so it doesn't change an element's basic nature, though that gets very fuzzy in practice. A span made block becomes a bully that kicks everything else off the line, which is very un-inline sort of behaviour.
So, to mitigate against possible conflicts between their natural and css-induced behaviours, it is better to allow:
div or any natural block tag to only ever be block or inline-block.
span or any natural inline tag to only ever be inline or inline-block.
This will also mitigate against tending to build page structures that will likely end up churning out error and warning messages.
Basically, NEVER embed a natural block tag inside a natural inline tag, at any depth.
Why there is a really a distinction is perhaps due to a simplistic idea of what HTML was going to be used for when it was first dreamed up.
Certainly, framework makers got around a lot of these what-to-embed-where problems by just using myriads of divs everywhere, and 'divitis' was born, and still alive and well in every framework. Just have to press F12 in a browser on almost any commercial web page and drill down through a dozen divs. This very page has 15 unbroken levels of divs.
It is not hard to see why just settling on divs made sense. For example, a p tag may have a bunch of links to various sites, and that is ok because inline links are allowed in a block p. However, if not wanting to have query variables visible in those urls, then buttons are required. If only one, then the p can be put inside a form, as a p cannot contain a form.
The formaction attribute on a button can be used to target a url other than the form default, but it still does not allow independent forms, each with their own set of hidden inputs. A button can use the form attribute to use it with a form that isn't an ancestor, but it can get messy to keep track of.
For multiple links to different sites to appear as part of one paragraph though, the only way is to use a div instead of the p and then wrap each button in its own form set to inline. Most frameworks have to cope with so much more complex scenarios that nested divs are the only way to go.
It meant that they really only had to manage one tag per purpose and manage it as if it was an isolated environment. So what was meant to be an occasionally-used functional grouping tag became the web's Lego block. And none of them are going to risk breaking their frameworks by converting to HTML5 semantic tags in a hurry. In the end, semantic tags only really work for fairly static content rather than rich interactive sites.
I had tried to create custom solution using jQuery, which would imitate same behavior as a tag does, for parent DIV.
DEMO:
https://jsfiddle.net/kutec/m9vxhcke/
As per W3C standard, you cannot do this:
<div class="boxes">
<a href="http://link1.com" target="_blank">
<div class="box">
<h3>Link with _blank attr</h3>
</div>
</a>
</div>
You must follow this:
<div class="boxes">
<div class="box">
<h3>
Link with _blank attr
</h3>
</div>
</div>
But by following above code, you wouldn't get the whole DIV clickable :).
Correct structure should be something like this, which also allows you to click over the DIV to redirect on the given href value:
<div class="boxes" data-href="http://link1.com" data-target="_blank">
<div class="box">
<h3>
Link with _blank attr
</h3>
</div>
</div>
Simple Solution:
$(function() {
$('.boxes a').each(function(){
var aTag = $(this).attr('href');
$(this).parent().attr('data-href',aTag);
$("[data-href]").click(function() {
window.location.href = $(this).attr("data-href");
return false;
});
})
}(jQuery));
Dynamic Solution:
(function ( $ ) {
$.fn.dataURL = function() {
// variables
var el = $(this);
var aTag = el.find('a');
var aHref;
var aTarget;
// get & set attributes
aTag.each(function() {
var aHref = $(this).attr('href');
$(this).parent().attr('data-href',this);
aTarget = $(this).attr('target');
$(this).parent().attr('data-target',aTarget);
});
// imitation - default attributes' behavior on "data-" attributes
$(el).delegate('[data-href]','click', function() {
var loc = window.location.href;
loc = $(this).attr("data-href");
aTarget = $(this).attr('data-target');
if(aTarget == "_blank"){
window.open(loc);
} else {
window.location = loc;
}
return false;
});
//removing attributes from selector itself
el.removeAttr('data-href');
el.removeAttr('data-target');
// css
$('[data-href]').css('cursor','pointer');
};
}( jQuery ));
Final call:
<script>
$('.boxes').dataURL();
</script>
Hope this would be helpful :)
You would just want to style the "a" tag as display: block;
Eclipse is appropriately telling you that your HTML is not to spec (as a div tag is not allowed in an anchor tag).
But, since you seem to want to be visually making the anchor look like a big-ol-box, then simply style it as such :)
One easy way to make the div a link/clickable is by using html javascript onclick attribute:
<div class="clickable-div" onclick="location.href='#';"><div> ... </div></div>

dojo/dijit and Printing

I want to be able to provide a button to my users to just print a particular portion of my dojo/dijit application. There seems to be a general lack of documentation and examples when it comes to printing.
For example, I have a specific dijit.layout.ContentPane that contains the content that I would like to print, but I wouldn't want to print the rest of the document. I have seen some pure JavaScript examples on the web where the node.innerHTML is read into a "hidden" iframe and then printed from there. I suspect that would work, but I was wondering if there was a more dojo centric approach to printing.
Any thoughts?
I have decided to go down the path of reading into <iframe> and printing from there, but because I am using a rendered dojox.gfx surface, a direct read from the target ContentPane to the invisible iframe did not work correctly in some browsers. So what I do is set the "src" of the iframe to a page which re-renders the diagram and then prints itself out when it is finished. In the main document it looks something like this:
<iframe id="printIFrame4" src="#" style="width: 0px; height:0px;
border: none; background: transparent"></iframe>
<button dojoType="dijit.form.Button" style="margin-top: -3px;" id="buttonPrintMap4">
Print...
<script type="dojo/method" event="onClick" args="event">
dojo.byId("printIFrame4").src = "logmap/docMap.php?id=4";
</script>
</button>
And then the page does the necessary dojo stuff to redrew the diagram and then once it is loaded it does a:
this.focus();
this.print();
Which then follows through with the printing.
One solution would be to create a print-only stylesheet while the first rule hiding everything by default:
body {
display: none;
}
Then, a second CSS rule, also in your print-only stylesheet, displays only the Dojo content pane:
#contentPaneId {
display: block;
}
The Dojo ContentPane ID needs to match what you use for #contentPaneId in the CSS.
Finally, you can instruct browsers that it's a print-only CSS file using media="print" in your link tag:
<link rel="stylesheet" type="text/css" href="printOnly.css" media="print"/>

Categories