Skip to content

Commit ae37f83

Browse files
committed
Add :dir support to Polymer 1
Polymer 1.x fix for #4860 `:dir` becomes `:host-context([dir])`
1 parent db0a932 commit ae37f83

File tree

3 files changed

+191
-1
lines changed

3 files changed

+191
-1
lines changed

src/lib/style-transformer.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
3838
* :host-context(...): scopeName..., ... scopeName
3939
40+
* ...:dir(ltr|rtl) -> [dir="ltr|rtl"] ..., ...[dir="ltr|rtl"]
41+
42+
* :host(:dir[rtl]) -> scopeName:dir(rtl) -> [dir="rtl"] scopeName, scopeName[dir="rtl"]
43+
4044
*/
4145
var api = {
4246

@@ -105,6 +109,11 @@
105109
cb = function(rule) {
106110
rule.selector = self._slottedToContent(rule.selector);
107111
rule.selector = rule.selector.replace(ROOT, ':host > *');
112+
rule.selector = rule.selector.split(',').map(function(s) {
113+
s = s.replace(HOST_DIR, HOST_DIR_REPLACE);
114+
s = s.replace(DIR_PAREN, SHADOW_DIR_REPLACE);
115+
return s;
116+
}).join(',');
108117
if (callback) {
109118
callback(rule);
110119
}
@@ -238,6 +247,7 @@
238247
selector = selector.replace(SCOPE_JUMP, ' ');
239248
stop = true;
240249
}
250+
selector = selector.replace(DIR_PAREN, DIR_REPLACE);
241251
return {value: selector, combinator: combinator, stop: stop,
242252
hostContext: hostContext};
243253
},
@@ -340,6 +350,11 @@
340350
var SELECTOR_NO_MATCH = 'should_not_match';
341351
var SLOTTED_PAREN = /(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
342352
var HOST_OR_HOST_GT_STAR = /:host(?:\s*>\s*\*)?/;
353+
var DIR_PAREN = /(.*):dir\((ltr|rtl)\)/g;
354+
var DIR_REPLACE = '[dir="$2"] $1, $1[dir="$2"]';
355+
var SHADOW_DIR_REPLACE = ':host-context([dir="$2"]) $1';
356+
var HOST_DIR = /:host\(:dir\((rtl|ltr)\)\)/g;
357+
var HOST_DIR_REPLACE = ':host-context([dir="$1"])';
343358

344359
// exports
345360
return api;

test/runner.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@
9494
'unit/script-after-import-in-head.html',
9595
'unit/globals.html',
9696
'unit/lazy-register.html',
97-
'unit/element-disable-upgrade.html'
97+
'unit/element-disable-upgrade.html',
98+
'unit/dir.html',
99+
'unit/dir.html?dom=shadow',
100+
'unit/dir.html?lazyRegister=true&useNativeCSSProperties=true',
101+
'unit/dir.html?lazyRegister=true&useNativeCSSProperties=true&dom=shadow'
98102
];
99103

100104
if (window.customElements || document.registerElement) {

test/unit/dir.html

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<!doctype html>
2+
<!--
3+
@license
4+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
5+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
6+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
7+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
8+
Code distributed by Google as part of the polymer project is also
9+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
10+
-->
11+
<html dir="rtl">
12+
<head>
13+
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
14+
<script src="../../../web-component-tester/browser.js"></script>
15+
<link rel="import" href="../../polymer.html">
16+
</head>
17+
<body>
18+
<!--
19+
Issues
20+
1. regex will process entire string, including comments and properties, not just selectors...
21+
2. complex selectors. not ok... e.g.
22+
bad: .special > *:dir(rtl)
23+
but ok: .special:dir(rtl) > *
24+
3. multiple selectors per line? ok.
25+
-->
26+
<dom-module id="x-inner-dir">
27+
<template>
28+
<style>
29+
:host {
30+
display: block;
31+
height: 20px;
32+
color: white;
33+
}
34+
input, section {
35+
border-top-width: 0px;
36+
}
37+
38+
section:dir(rtl), input:dir(rtl) {
39+
border: 10px solid rgb(123, 123, 123);
40+
}
41+
42+
.special:dir(rtl) > * {
43+
color: rgb(0, 128, 0);
44+
}
45+
</style>
46+
<div>no rtl styling</div>
47+
<section>rtl styling</section>
48+
<input value="rtl styling">
49+
<div class="special">
50+
<div>at the right.</div>
51+
</div>
52+
</template>
53+
<script>
54+
addEventListener('WebComponentsReady', function() {
55+
Polymer({is: 'x-inner-dir'});
56+
});
57+
</script>
58+
</dom-module>
59+
60+
<dom-module id="x-dir">
61+
<template>
62+
<style>
63+
:host {
64+
display: block;
65+
background-color: rgb(0, 0, 255);
66+
min-height: 100px;
67+
width: 100px;
68+
}
69+
:host(:dir(rtl)) {
70+
background-color: rgb(0, 128, 0);
71+
}
72+
#foo:dir(rtl) {
73+
border: 10px solid rgb(255, 0, 0);
74+
}
75+
.thing:dir(rtl) {
76+
border: 10px solid rgb(0, 0, 255);
77+
}
78+
</style>
79+
<div id="foo"></div>
80+
<div class="thing"></div>
81+
<x-inner-dir></x-inner-dir>
82+
</template>
83+
<script>
84+
addEventListener('WebComponentsReady', function() {
85+
Polymer({is: 'x-dir'});
86+
});
87+
</script>
88+
</dom-module>
89+
90+
<test-fixture id="dir">
91+
<template>
92+
<x-dir></x-dir>
93+
</template>
94+
</test-fixture>
95+
96+
<test-fixture id="preset">
97+
<template>
98+
<x-inner-dir dir="ltr"></x-inner-dir>
99+
</template>
100+
</test-fixture>
101+
102+
<script>
103+
function assertComputed(node, expected, property) {
104+
property = property || 'border-top-width';
105+
var actual = getComputedStyle(node).getPropertyValue(property).trim();
106+
assert.equal(expected, actual);
107+
}
108+
109+
suite(':dir', function() {
110+
teardown(function() {
111+
document.documentElement.setAttribute('dir', 'rtl');
112+
});
113+
114+
test(':dir(rtl) functions when html element dir attr set to rtl', function() {
115+
var el = fixture('dir');
116+
var elRoot = Polymer.dom(el.root);
117+
assertComputed(el, 'rgb(0, 128, 0)', 'background-color');
118+
assertComputed(elRoot.querySelector('#foo'), '10px');
119+
assertComputed(elRoot.querySelector('.thing'), '10px');
120+
var inner = elRoot.querySelector('x-inner-dir');
121+
var innerRoot = Polymer.dom(inner.root);
122+
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(0, 128, 0)', 'color');
123+
assertComputed(innerRoot.querySelector('section'), '10px');
124+
assertComputed(innerRoot.querySelector('input'), '10px');
125+
});
126+
127+
test(':dir reacts to html attribute changing', function(done) {
128+
var el = fixture('dir');
129+
var elRoot = Polymer.dom(el.root);
130+
document.documentElement.setAttribute('dir', 'ltr');
131+
requestAnimationFrame(function() {
132+
assertComputed(el, 'rgb(0, 0, 255)', 'background-color');
133+
assertComputed(elRoot.querySelector('#foo'), '0px');
134+
assertComputed(elRoot.querySelector('.thing'), '0px');
135+
var inner = elRoot.querySelector('x-inner-dir');
136+
var innerRoot = Polymer.dom(inner.root);
137+
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');
138+
assertComputed(innerRoot.querySelector('section'), '0px');
139+
assertComputed(innerRoot.querySelector('input'), '0px');
140+
done();
141+
});
142+
});
143+
144+
test('elements with dir attribute explicitly set will not change', function() {
145+
this.skip();
146+
var inner = fixture('preset');
147+
var innerRoot = Polymer.dom(inner.root);
148+
assert.equal(document.documentElement.getAttribute('dir'), 'rtl');
149+
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');
150+
assertComputed(innerRoot.querySelector('section'), '0px');
151+
assertComputed(innerRoot.querySelector('input'), '0px');
152+
});
153+
154+
test('elements will adopt dir status when reconnected', function(done) {
155+
var el = fixture('dir');
156+
assertComputed(el, 'rgb(0, 128, 0)', 'background-color');
157+
var parent = el.parentNode;
158+
parent.removeChild(el);
159+
document.documentElement.setAttribute('dir', 'ltr');
160+
requestAnimationFrame(function() {
161+
parent.appendChild(el);
162+
requestAnimationFrame(function() {
163+
assertComputed(el, 'rgb(0, 0, 255)', 'background-color');
164+
done();
165+
});
166+
});
167+
});
168+
});
169+
</script>
170+
</body>
171+
</html>

0 commit comments

Comments
 (0)