Polymer template and style tag relation - polymer

I know that Polymer recommends to use style tag inside template tag since v1.1 but supports both. Can anyone tell me the advantages of doing so. If it is inertness then can you please give an example where keeping style tag outside template exposed it outside of shadow-dom

The 1.1 release notes indicate performance reasons:
Previously, we recommended that a <style> element should be placed inside an element's <dom-module> but outside of its template. This is still supported, but we've now optimized placing styles within the template itself, so having the <style> tag outside of the template will be slower.
If I read the code correctly, this is Polymer's procedure for parsing CSS:
Select child nodes that can contain CSS (including <style> and <template>).
For each node:
a. If the node is <template>, recurse on the node (go to step 1).
b. Else if the node is <style>, remove the node (to prevent style leak), and then append the node's text to the string buffer.
c. Else if the node is <link rel="import" type="css">, append its imported text to the string buffer.
Return the string buffer.
If all styles are parsed using this procedure, I don't understand how the placement of <style> would affect performance (maybe I'm missing something).
please give an example where keeping style tag outside template exposed it outside of shadow-dom
The <style> doesn't leak regardless of whether it's placed inside the <template> (because of step 2b above), as seen in the following demos.
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<div class="title">outside <x-foo> (should not be styled)</div>
<dom-module id="x-foo">
<style>
div.title {
font-family: Arial;
color: blue;
}
</style>
<template>
<div class="title">inside <x-foo></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo'
});
});
</script>
</dom-module>
</body>
codepen
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<div class="title">outside <x-foo> (should not be styled)</div>
<dom-module id="x-foo">
<template>
<style>
div.title {
font-family: Arial;
color: blue;
}
</style>
<div class="title">inside <x-foo></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo'
});
});
</script>
</dom-module>
</body>
codepen

Related

How to access innerHTML of a template in the content of an element

First off, I apologize for the title-gore. I struggled to summarize this issue in a single sentence.
I have a Polymer element. In my element, I wish to display (or simply log to console) the innerHTML of a template element that is a child of (contents of) the element instance.
(Please note that the intent here is to create an element similar to the demo-snippet of iron-demo-helpers.)
Consider the following Polymer element:
<link rel="import" href="../../polymer/polymer.html">
<dom-module id="print-contents-html">
<script>
Polymer({
is: 'print-contents-html',
attached: function() {
var template = Polymer.dom(this).queryDistributedElements('template')[0];
console.log(template.innerHTML);
}
});
</script>
</dom-module>
Very simply, I query for the 'template' element and log its inner HTML.
Now consider the following usage:
<!doctype html>
<html>
<head>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="./print-contents-html.html">
</head>
<body>
<print-contents-html>
<template>
Hello World
</template>
</print-contents-html>
</body>
</html>
As expected, this results in "Hello World" being logged to the console.
However, I am trying to make use of the 'print-contents-html' element within another Polymer element:
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="./print-contents-html.html">
<dom-module id="simple-demo">
<template>
<print-contents-html>
<template>
Hello World from simple demo
</template>
</print-contents-html>
</template>
<script>
Polymer({
is: 'simple-demo',
});
</script>
</dom-module>
Now if I update the usage to also include an instance of the simple-demo element:
<!doctype html>
<html>
<head>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="./print-contents-html.html">
<link rel="import" href="./simple-demo.html">
</head>
<body>
<print-contents-html>
<template>
Hello World
</template>
</print-contents-html>
<simple-demo></simple-demo>
</body>
</html>
I would expect to see both "Hello World" and "Hello World from simple demo" logged to the console. However the simple demo message is not logged.
It appears that while the queryDistributedElements() does return the instance of the template element, the innerHTML field is an empty string.
Does anyone know why this is the case? That accessing the content/child template element does not have its innerHTML set?
Secondly, does anyone know of an alternative method through which I can access the innerHTML of the template element that is a content/child of a polymer element?
Kind Regards,
Andrew Butler
This issue is discussed in Polymer's Github repository.
The solution is to add a preserve-content attribute it the inner <template> tag:
<dom-module id="simple-demo">
<template>
<print-contents-html>
<template preserve-content>
Hello World from simple demo
</template>
</print-contents-html>
</template>
...
Then it works!

Polymer 1.x: Is google-chart temporarily down via polygit?

In this jsBin, I am trying to display a google-chart element by copypasting the first example from the docs page here. But the chart does not display.
Can anyone confirm or reject my hypothesis that the reason the bin is not working is because of a similar temporary server issue at polygit2.appspot.com (similar to this case of two days ago)? Or is there something wrong with the code that needs fixing?
http://jsbin.com/dusaqaqaje/edit?html,console,output
<!doctype html>
<head>
<meta charset="utf-8">
<!---- >
<base href="https://polygit.org/components/">
<!---- >
Toggle below/above as backup when server is down
<!---->
<base href="https://polygit2.appspot.com/components/">
<!---->
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="paper-button/paper-button.html" rel="import">
<link href="google-chart/google-chart.html" rel="import">
</head>
<body>
<dom-module id="x-element">
<template>
<style></style>
<paper-button on-tap="_handleTap">Click Me</paper-button>
<!---- >
Below is just a copypaste from the docs page here:
https://elements.polymer-project.org/elements/google-chart
<!---->
<google-chart
type='pie'
options='{"title": "Distribution of days in 2001Q1"}'
cols='[{"label":"Month", "type":"string"}, {"label":"Days", "type":"number"}]'
rows='[["Jan", 31],["Feb", 28],["Mar", 31]]'>
</google-chart>
</template>
<script>
(function(){
Polymer({
is: "x-element",
properties: {
},
_handleTap: function() {
console.log('You clicked me!');
},
});
})();
</script>
</dom-module>
<x-element></x-element>
</body>
I think it's a temporary server issue, as you already proposed. Importing this google-chart element via polygit just throws an error instead of serving the element (you may see this behaviour in your import link).
Hopefully this will be fixed soon.

Polymer 1.0: Referencing a path for an imported style sheet using a custom-style

I'm trying to understand this example.
Code
<link rel="import" href="../../styles/app-theme.html"> <!--Line 22-->
...
<style is="custom-style" include="app-theme"></style> <!--Line 32-->
Question
In line 32, does the app-theme value for the include attribute refer to the app-theme.html import in line 22? If so, how does the compiler discover the path of the app-theme.html import if it's not included somewhere in the <style> tag's set of attributes?
It really just references the id of the dom-module with the style you want to use.
<dom-module id="app-theme">
<template>
<style>
.red { color: red; }
</style>
</template>
</dom-module>

Polymer 1.0 Extending Elements - paper-dialog with custom element

I am am trying to create a custom element that plays a youtube video in paper-dialog. So videoPlayer = Polymer.dom(this.root).querySelector('video-player'); inherits/has access to that paper-dialogs open method, I am trying to extend my custom element. It isn't working, but hopefully I am on the right track and someone can show me correctly.
I am using Polymer 1.0, but I only have https://www.polymer-project.org/0.5/docs/polymer/polymer.html#extending-other-elements to go by for extending elements.
<link rel="import" href="../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/google-youtube/google-youtube.html">
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="video-player">
<template>
<div class="layout horizontal">
<paper-button dialog-dismiss>
<paper-icon-button icon="arrow-back"></paper-icon-button>
</paper-button>
</div>
<div style="height: 100%; width: 100%">
<google-youtube style="height: 100%;"
video-id="YMWd7QnXY8E"
rel="1"
start="5"
playsinline="0"
controls="2"
showinfo="0"
width="100%"
height="100%"
autoplay="1">
</google-youtube>
</div>
</template>
<script>
Polymer({
is: "video-player"
});
</script>
<paper-dialog name="video-player" extends="video-player">
<template>
<shadow></shadow>
</template>
<script>
Polymer();
</script>
</paper-dialog>
<video-player></video-player>
As was mentioned in the comments, you can't yet extend custom elements, so the existing pattern (or at least the one I use) is to make use of behaviors wherever possible and wrappers wherever not.
e.g.
<dom-module id="popup-video-player">
<template>
<video-player></video-player>
</template>
<script>
Polymer({
is: 'popup-video-player',
behaviors: [Polymer.PaperDialogBehavior],
...
});
</script>
</dom-module>
Now you can use <popup-video-player> just like a paper-dialog.
I know it stinks because if video-player has a bunch of properties that you want access to, you have to copy them in the popup-video-player element's API, which is not exactly DRY.
If you look at the paper-input source, you'll see them doing the same thing. It's obvious that they want to extend iron-input, but they can't so you get things like this:
<input is="iron-input" id="input"
aria-labelledby$="[[_ariaLabelledBy]]"
aria-describedby$="[[_ariaDescribedBy]]"
disabled$="[[disabled]]"
title$="[[title]]"
... >
As a side note, you could always hook into the <video-player>s "properties" property and make the API additions programatically.
maybe something like this would work: (untested!)
Polymer({
...
properties: (function () {
var prop = {
//special properties specific to the pop up version of video-player
//..obviously be careful to avoid name space conflicts.
};
var video_player = document.createElement('video-player');
video_player.properties.keys().forEach( function(key) {
props[key] = video_player[key];
});
return props;
}()),
});

Understanding the constructor attribute in Polymer elements

A Polymer noob...
I'm trying to create a custom element as per the Polymer API docs, where my main page looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Polymer</title>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
</head>
<body>
<div id="test"></div>
<polymer-element name="book-template" constructor="BookTemplate" noscript>
<template>
<style>
h1 { color: orange; }
</style>
<h1>Hello from some-foo</h1>
</template>
</polymer-element>
</body>
</html>
I know that the page content will render if I just put <book-template></book-template> on the page, or if I do something like this inside the <body> tag:
<script>
var book = document.createElement('book-template');
document.getElementById('test').appendChild(book);
</script>
But I'm trying to utilize the element's constructor attribute, assuming that this will create the element when placed somewhere inside of <body>:
<script>
var book = new BookTemplate();
</script>
...but getting a console message that BookTemplate() is not defined.
I'm sure it's something simple...any idea? Thanks in advance.
I guess you have to wait for the polymer-ready event, so that the constructor is available in the global window object http://jsbin.com/kosuf/2/edit?html,console,output:
<script>
document.addEventListener('polymer-ready',function() {
var book = new BookTemplate();
if (book) {
console.log('Ok');
}
});
</script>