Skip to content

Commit

Permalink
Merge pull request #4881 from Polymer/1.x-dir-selector
Browse files Browse the repository at this point in the history
Add :dir support to Polymer 1
  • Loading branch information
dfreedm authored Oct 13, 2017
2 parents db0a932 + fad613e commit 5c0df2d
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/lib/style-transformer.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
* :host-context(...): scopeName..., ... scopeName
* ...:dir(ltr|rtl) -> [dir="ltr|rtl"] ..., ...[dir="ltr|rtl"]
* :host(:dir[rtl]) -> scopeName:dir(rtl) -> [dir="rtl"] scopeName, scopeName[dir="rtl"]
*/
var api = {

Expand Down Expand Up @@ -105,6 +109,11 @@
cb = function(rule) {
rule.selector = self._slottedToContent(rule.selector);
rule.selector = rule.selector.replace(ROOT, ':host > *');
rule.selector = rule.selector.split(',').map(function(s) {
s = s.replace(HOST_DIR, HOST_DIR_REPLACE);
s = s.replace(DIR_PAREN, SHADOW_DIR_REPLACE);
return s;
}).join(',');
if (callback) {
callback(rule);
}
Expand Down Expand Up @@ -238,6 +247,7 @@
selector = selector.replace(SCOPE_JUMP, ' ');
stop = true;
}
selector = selector.replace(DIR_PAREN, DIR_REPLACE);
return {value: selector, combinator: combinator, stop: stop,
hostContext: hostContext};
},
Expand Down Expand Up @@ -340,6 +350,11 @@
var SELECTOR_NO_MATCH = 'should_not_match';
var SLOTTED_PAREN = /(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
var HOST_OR_HOST_GT_STAR = /:host(?:\s*>\s*\*)?/;
var DIR_PAREN = /(.*):dir\((ltr|rtl)\)/g;
var DIR_REPLACE = '[dir="$2"] $1, $1[dir="$2"]';
var SHADOW_DIR_REPLACE = ':host-context([dir="$2"]) $1';
var HOST_DIR = /:host\(:dir\((rtl|ltr)\)\)/g;
var HOST_DIR_REPLACE = ':host-context([dir="$1"])';

// exports
return api;
Expand Down
6 changes: 5 additions & 1 deletion test/runner.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@
'unit/script-after-import-in-head.html',
'unit/globals.html',
'unit/lazy-register.html',
'unit/element-disable-upgrade.html'
'unit/element-disable-upgrade.html',
'unit/dir.html',
'unit/dir.html?dom=shadow',
'unit/dir.html?lazyRegister=true&useNativeCSSProperties=true',
'unit/dir.html?lazyRegister=true&useNativeCSSProperties=true&dom=shadow'
];

if (window.customElements || document.registerElement) {
Expand Down
175 changes: 175 additions & 0 deletions test/unit/dir.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html dir="rtl">
<head>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer.html">
</head>
<body>
<!--
Issues
1. regex will process entire string, including comments and properties, not just selectors...
2. complex selectors. not ok... e.g.
bad: .special > *:dir(rtl)
but ok: .special:dir(rtl) > *
3. multiple selectors per line? ok.
-->
<dom-module id="x-inner-dir">
<template>
<style>
:host {
display: block;
height: 20px;
color: white;
}
input, section {
border-top-width: 0px;
}

section:dir(rtl), input:dir(rtl) {
border: 10px solid rgb(123, 123, 123);
}

.special:dir(rtl) > * {
color: rgb(0, 128, 0);
}
</style>
<div>no rtl styling</div>
<section>rtl styling</section>
<input value="rtl styling">
<div class="special">
<div>at the right.</div>
</div>
</template>
<script>
addEventListener('WebComponentsReady', function() {
Polymer({is: 'x-inner-dir'});
});
</script>
</dom-module>

<dom-module id="x-dir">
<template>
<style>
:host {
display: block;
background-color: rgb(0, 0, 255);
min-height: 100px;
width: 100px;
}
:host(:dir(rtl)) {
background-color: rgb(0, 128, 0);
}
#foo:dir(rtl) {
border: 10px solid rgb(255, 0, 0);
}
.thing:dir(rtl) {
border: 10px solid rgb(0, 0, 255);
}
</style>
<div id="foo"></div>
<div class="thing"></div>
<x-inner-dir></x-inner-dir>
</template>
<script>
addEventListener('WebComponentsReady', function() {
Polymer({is: 'x-dir'});
});
</script>
</dom-module>

<test-fixture id="dir">
<template>
<x-dir></x-dir>
</template>
</test-fixture>

<test-fixture id="preset">
<template>
<x-inner-dir dir="ltr"></x-inner-dir>
</template>
</test-fixture>

<script>
function assertComputed(node, expected, property) {
property = property || 'border-top-width';
var actual = getComputedStyle(node).getPropertyValue(property).trim();
assert.equal(expected, actual);
}

suite(':dir', function() {
teardown(function() {
document.documentElement.setAttribute('dir', 'rtl');
});

test(':dir(rtl) functions when html element dir attr set to rtl', function() {
var el = fixture('dir');
var elRoot = Polymer.dom(el.root);
assertComputed(el, 'rgb(0, 128, 0)', 'background-color');
assertComputed(elRoot.querySelector('#foo'), '10px');
assertComputed(elRoot.querySelector('.thing'), '10px');
var inner = elRoot.querySelector('x-inner-dir');
var innerRoot = Polymer.dom(inner.root);
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(0, 128, 0)', 'color');
assertComputed(innerRoot.querySelector('section'), '10px');
assertComputed(innerRoot.querySelector('input'), '10px');
});

test(':dir reacts to html attribute changing', function(done) {
var el = fixture('dir');
var elRoot = Polymer.dom(el.root);
document.documentElement.setAttribute('dir', 'ltr');
requestAnimationFrame(function() {
assertComputed(el, 'rgb(0, 0, 255)', 'background-color');
assertComputed(elRoot.querySelector('#foo'), '0px');
assertComputed(elRoot.querySelector('.thing'), '0px');
var inner = elRoot.querySelector('x-inner-dir');
var innerRoot = Polymer.dom(inner.root);
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');
assertComputed(innerRoot.querySelector('section'), '0px');
assertComputed(innerRoot.querySelector('input'), '0px');
done();
});
});

test('elements with dir attribute explicitly set will not change', function() {
/*
Both the polyfill and native ShadowDOM transforms to the `:dir` selector do not support
per-instance opt-out at this time.
*/
this.skip();
var inner = fixture('preset');
var innerRoot = Polymer.dom(inner.root);
assert.equal(document.documentElement.getAttribute('dir'), 'rtl');
assertComputed(innerRoot.querySelector('.special > div'), 'rgb(255, 255, 255)', 'color');
assertComputed(innerRoot.querySelector('section'), '0px');
assertComputed(innerRoot.querySelector('input'), '0px');
});

test('elements will adopt dir status when reconnected', function(done) {
var el = fixture('dir');
assertComputed(el, 'rgb(0, 128, 0)', 'background-color');
var parent = el.parentNode;
parent.removeChild(el);
document.documentElement.setAttribute('dir', 'ltr');
requestAnimationFrame(function() {
parent.appendChild(el);
requestAnimationFrame(function() {
assertComputed(el, 'rgb(0, 0, 255)', 'background-color');
done();
});
});
});
});
</script>
</body>
</html>

0 comments on commit 5c0df2d

Please sign in to comment.