Reputation: 5692
I'm writing a custom <figure>
-like element for which I'd like to put a <figcaption>
under the main content. The <figcaption>
needs to include some content (text with potential formatting) from the child nodes of the custom element, for which I'm using <content select="span.caption"></content>
. However, per the Shadow DOM spec, the <span>
has already been distributed to the earlier <content></content>
element that laid out the body of the custom element.
I've tried using <content select=":not(span.caption)"></content>
to avoid distributing the caption, but that appears not to be a compound selector and matches nothing.
What's the recommended way to get the elements to render in the order I want?
Here's the code with the problem, which is also at http://jsbin.com/vizoqusu/3/edit:
<!DOCTYPE html>
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/0.1.4/platform.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/0.1.4/polymer.js"></script>
<meta charset="utf-8">
</head>
<body>
<polymer-element name="my-figure" noscript>
<template>
<figure>
<content></content>
<figcaption>Figure 7: <content select="span.caption"></content></figcaption>
</figure>
</template>
</polymer-element>
<my-figure>
Hello World!
<span class="caption">The caption</span>
</my-figure>
</body>
</html>
Upvotes: 3
Views: 614
Reputation: 11027
This actually does work today under ShadowDOM polyfill, with two caveats:
*:not(.caption)
Here is an example:
http://jsbin.com/vizoqusu/5/edit
<polymer-element name="my-figure" noscript>
<template>
<figure>
<content select="*:not(.caption)"></content>
<figcaption>Figure 7: <content select="span.caption"></content></figcaption>
</figure>
</template>
</polymer-element>
<my-figure>
<span>Hello World!</span>
<span class="caption">The caption</span>
</my-figure>
As for the native system, I used your use case to argue for inclusion of :not() into the specification, you can see it here:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=24867
Upvotes: 2
Reputation: 2918
I see a few options here:
You could use getDistributedNodes
to first get the content of the element and then inject the text (Hello World) and caption at the right points as follows:
<polymer-element name="my-figure">
<template>
<figure id="figureHolder">
<content id="content"></content>
<figcaption>Figure 7: <content id="caption" select="span.caption"></content></figcaption>
</figure>
</template>
<script>
Polymer('my-figure', {
caption: '',
ready: function() {
var nodes = this.$.content.getDistributedNodes();
this.$.caption.innerHTML = nodes[1].innerHTML;
this.$.content.getDistributedNodes()[0].data = nodes[0].data;
this.$.content.getDistributedNodes()[1].innerHTML = '';
}
});
</script>
</polymer-element>
<my-figure>
Hello World!
<span class="caption">The caption</span>
</my-figure>
You could move your caption into an attribute and this allows you to maintain a clean separation between the content of your figure and the caption itself:
<polymer-element name="my-figure" attributes="caption" noscript>
<template>
<figure>
<content></content>
<figcaption>Figure 7: {{caption}} </figcaption>
</figure>
</template>
</polymer-element>
<my-figure caption="The caption">
Hello World!
</my-figure>
You could move your main content (e.g Hello World
) into it's own span
and add a class to allow targeting it from inside your template
directly, so:
<polymer-element name="my-figure" noscript>
<template>
<figure>
<content select="span.hello"></content>
<figcaption>Figure 7:
<content select="span.caption"></content></figcaption>
</figure>
</template>
</polymer-element>
<my-figure>
<span class="hello">Hello World!</span>
<span class="caption">The caption</span>
</my-figure>
Upvotes: 2