Skip to content

Commit ec6b2f2

Browse files
committed
style processing refactoring and fix for #148
1 parent 1b7c365 commit ec6b2f2

File tree

5 files changed

+131
-56
lines changed

5 files changed

+131
-56
lines changed

src/styling.js

+78-56
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
// imports
1010
var log = window.logFlags || {};
1111

12-
var doc = window.ShadowDOMPolyfill ? ShadowDOMPolyfill.wrap(document) : document;
12+
var doc = wrap(document);
1313

1414
/**
1515
* Install external stylesheets loaded in <element> elements into the
1616
* element's template.
1717
* @param inElementElement The <element> element to style.
1818
*/
19-
function installSheets(inElementElement) {
20-
installLocalSheets(inElementElement);
21-
installGlobalStyles(inElementElement);
19+
function installSheets(elementElement) {
20+
installLocalSheets(elementElement);
21+
installGlobalStyles(elementElement);
2222
}
2323

2424
/**
@@ -30,23 +30,24 @@
3030
* Note, ignores sheets with the attribute 'polymer-scope'.
3131
* @param inElementElement The <element> element to style.
3232
*/
33-
function installLocalSheets(inElementElement) {
34-
var sheets = inElementElement.querySelectorAll('[rel=stylesheet]');
35-
var template = inElementElement.querySelector('template');
36-
if (template) {
37-
var content = templateContent(template);
38-
}
33+
function installLocalSheets(elementElement) {
34+
var sheets = findInElement(elementElement, SHEET_SELECTOR, function(s) {
35+
return !s.hasAttribute(SCOPE_ATTR);
36+
});
37+
var content = elementTemplateContent(elementElement);
3938
if (content) {
40-
forEach(sheets, function(sheet) {
41-
if (!sheet.hasAttribute(SCOPE_ATTR)) {
42-
// in case we're in document, remove from element
43-
sheet.parentNode.removeChild(sheet);
44-
var style = createStyleElementFromSheet(sheet);
45-
if (style) {
46-
content.insertBefore(style, content.firstChild);
47-
}
39+
// in case we're in document, remove from element
40+
sheets.forEach(function(sheet) {
41+
sheet.parentNode.removeChild(sheet);
42+
});
43+
var fragment = document.createDocumentFragment();
44+
sheets.forEach(function(sheet) {
45+
var style = createStyleElementFromSheet(sheet);
46+
if (style) {
47+
fragment.appendChild(style);
4848
}
4949
});
50+
content.insertBefore(fragment, content.firstChild);
5051
}
5152
}
5253

@@ -59,13 +60,10 @@
5960
* @param inElementElement The <element> element to style.
6061
*/
6162
// TODO(sorvell): remove when wkb.ug/72462 is addressed.
62-
function installGlobalStyles(inElementElement) {
63-
var styles = inElementElement.globalStyles ||
64-
(inElementElement.globalStyles = findStyles(inElementElement, 'global'));
65-
applyStylesToScope(styles, doc.head);
63+
function installGlobalStyles(elementElement) {
64+
applyStylesToScope(findStyles(elementElement, 'global'), doc.head);
6665
}
6766

68-
6967
/**
7068
* Installs external stylesheets and <style> elements with the attribute
7169
* polymer-scope='controller' into the scope of inElement. This is intended
@@ -83,13 +81,16 @@
8381
* @param inElementElement The <element> containing controller styles.
8482
*/
8583
// TODO(sorvell): remove when spec issues are addressed
86-
function installControllerStyles(inElement, inElementElement) {
87-
var styles = inElementElement.controllerStyles ||
88-
(inElementElement.controllerStyles = findStyles(inElementElement, 'controller'));
84+
function installControllerStyles(element, elementElement) {
85+
if (!elementElement.controllerStyles) {
86+
elementElement.controllerStyles = findStyles(elementElement,
87+
'controller');
88+
}
89+
var styles = elementElement.controllerStyles;
8990
async.queue(function() {
90-
var scope = findStyleController(inElement);
91+
var scope = findStyleController(element);
9192
if (scope) {
92-
Polymer.shimPolyfillDirectives(styles, inElement.localName);
93+
Polymer.shimPolyfillDirectives(styles, element.localName);
9394
applyStylesToScope(styles, scope);
9495
}
9596
});
@@ -120,68 +121,89 @@
120121

121122
}
122123

123-
function findStyleController(inNode) {
124+
function findStyleController(node) {
124125
// find the shadow root that contains inNode
125-
var n = inNode;
126+
var n = node;
126127
while (n.parentNode && n.localName != 'shadow-root') {
127128
n = n.parentNode;
128129
}
129130
return n == doc ? doc.head : n;
130131
};
131132

132-
function createStyleElementFromSheet(inSheet) {
133-
if (inSheet.__resource) {
133+
function createStyleElementFromSheet(sheet) {
134+
if (sheet.__resource) {
134135
var style = doc.createElement('style');
135-
style.textContent = inSheet.__resource;
136+
style.textContent = sheet.__resource;
136137
return style;
137138
} else {
138-
console.warn('Could not find content for stylesheet', inSheet);
139+
console.warn('Could not find content for stylesheet', sheet);
139140
}
140141
}
141142

142-
function applyStylesToScope(inStyles, inScope) {
143-
inStyles.forEach(function(style) {
144-
inScope.appendChild(style.cloneNode(true));
143+
function applyStylesToScope(styles, scope) {
144+
styles.forEach(function(style) {
145+
scope.appendChild(style.cloneNode(true));
145146
});
146147
}
147148

148149
var eltProto = HTMLElement.prototype;
149150
var matches = eltProto.matches || eltProto.matchesSelector ||
150151
eltProto.webkitMatchesSelector || eltProto.mozMatchesSelector;
151-
function matchesSelector(inNode, inSelector) {
152+
function matchesSelector(node, inSelector) {
152153
if (matches) {
153-
return matches.call(inNode, inSelector);
154+
return matches.call(node, inSelector);
154155
}
155156
}
156157

157158
// TODO(sorvell): it would be better to identify blocks of rules within
158159
// style declarations than require different style/link elements.
159-
function findStyles(inElementElement, inDescriptor) {
160+
function findStyles(elementElement, descriptor) {
160161
var styleList = [];
161162
// handle stylesheets
162-
var sheets = inElementElement.querySelectorAll('[rel=stylesheet]');
163-
var selector = '[' + SCOPE_ATTR + '=' + inDescriptor + ']';
164-
Array.prototype.forEach.call(sheets, function(sheet) {
165-
if (matchesSelector(sheet, selector)) {
166-
// in case we're in document, remove from element
167-
sheet.parentNode.removeChild(sheet);
168-
styleList.push(createStyleElementFromSheet(sheet));
169-
}
163+
var selector = '[' + SCOPE_ATTR + '=' + descriptor + ']';
164+
var matcher = function(s) {
165+
return matchesSelector(s, selector);
166+
};
167+
var sheets = findInElement(elementElement, SHEET_SELECTOR, matcher);
168+
sheets.forEach(function(sheet) {
169+
// in case we're in document, remove from element
170+
sheet.parentNode.removeChild(sheet);
171+
styleList.push(createStyleElementFromSheet(sheet));
170172
});
171173
// handle style elements
172-
var styles = inElementElement.querySelectorAll('style');
173-
Array.prototype.forEach.call(styles, function(style) {
174-
if (matchesSelector(style, selector)) {
175-
// in case we're in document, remove from element
176-
style.parentNode.removeChild(style);
177-
styleList.push(style);
178-
}
174+
var styles = findInElement(elementElement, STYLE_SELECTOR, matcher);
175+
styles.forEach(function(style) {
176+
// in case we're in document, remove from element
177+
style.parentNode.removeChild(style);
178+
styleList.push(style);
179179
});
180180
return styleList;
181181
}
182182

183+
184+
function findInElement(elementElement, selector, matcher) {
185+
var nodes = arrayFromNodeList(elementElement
186+
.querySelectorAll(selector));
187+
var content = elementTemplateContent(elementElement);
188+
if (content) {
189+
var templateNodes = arrayFromNodeList(content
190+
.querySelectorAll(selector));
191+
nodes = nodes.concat(templateNodes);
192+
}
193+
return nodes.filter(matcher);
194+
}
195+
196+
function elementTemplateContent(elementElement) {
197+
var template = elementElement.querySelector('template');
198+
return template && templateContent(template);
199+
}
200+
201+
var STYLE_SELECTOR = 'style';
202+
var SHEET_SELECTOR = '[rel=stylesheet]';
183203
var SCOPE_ATTR = 'polymer-scope';
184-
var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
204+
function arrayFromNodeList(nodeList) {
205+
return Array.prototype.slice.call(nodeList || [], 0);
206+
}
185207

186208
// exports
187209
Polymer.installSheets = installSheets;

test/html/styling/sheet-order.html

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<!--
3+
Copyright 2013 The Polymer Authors. All rights reserved.
4+
Use of this source code is governed by a BSD-style
5+
license that can be found in the LICENSE file.
6+
-->
7+
<html>
8+
<head>
9+
<meta name="viewport" content="initial-scale=1.0">
10+
<title>Sheet order</title>
11+
<script src="../../../polymer.js"></script>
12+
<script src="../../../tools/test/htmltest.js"></script>
13+
<script src="../../../node_modules/chai/chai.js"></script>
14+
<link rel="import" href="x-sheets.html">
15+
<style>
16+
div {
17+
font-size: 10px;
18+
}
19+
</style>
20+
</head>
21+
<body>
22+
<x-sheets></x-sheets>
23+
</body>
24+
</html>

test/html/styling/sheet1.css

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.red1 {
2+
background: red;
3+
}
4+
5+
.yellow12 {
6+
background: black;
7+
}

test/html/styling/sheet2.css

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.blue2 {
2+
background: blue;
3+
}
4+
5+
.yellow12 {
6+
background: yellow;
7+
}

test/html/styling/x-sheets.html

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<element name="x-sheets">
2+
<link rel="stylesheet" href="sheet1.css">
3+
<link rel="stylesheet" href="sheet2.css">
4+
<style>
5+
.red1 {
6+
background: tomato;
7+
}
8+
</style>
9+
<template>
10+
<div class="red1">red</div>
11+
<div class="blue2">blue</div>
12+
<div class="yellow12">yellow12</div>
13+
</template>
14+
<script>Polymer.register(this)</script>
15+
</element>

0 commit comments

Comments
 (0)