Skip to content

Commit

Permalink
Merge pull request #43 from PolymerElements/fix-shadowdom-ripple
Browse files Browse the repository at this point in the history
Properly check if ripple-creating event happens within container with Shadow Dom
  • Loading branch information
dfreedm committed Nov 21, 2015
2 parents 9f02d41 + abe7d0a commit 4b244a5
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 13 deletions.
6 changes: 3 additions & 3 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "paper-behaviors",
"version": "1.0.9",
"version": "1.0.10",
"description": "Common behaviors across the paper elements",
"authors": [
"The Polymer Authors"
Expand All @@ -27,15 +27,15 @@
"dependencies": {
"iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
"iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
"polymer": "Polymer/polymer#^1.0.0"
"polymer": "Polymer/polymer#^1.2.1"
},
"devDependencies": {
"iron-component-page": "polymerelements/iron-component-page#^1.0.0",
"iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
"paper-material": "PolymerElements/paper-material#^1.0.0",
"paper-ripple": "PolymerElements/paper-ripple#^1.0.0",
"test-fixture": "PolymerElements/test-fixture#^1.0.0",
"web-component-tester": "*",
"web-component-tester": "^3.4.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
},
"ignore": []
Expand Down
18 changes: 10 additions & 8 deletions paper-ripple-behavior.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,25 @@
/**
* Ensures this element contains a ripple effect. For startup efficiency
* the ripple effect is dynamically on demand when needed.
* @param {!Event=} opt_triggeringEvent (optional) event that triggered the
* @param {!Event=} optTriggeringEvent (optional) event that triggered the
* ripple.
*/
ensureRipple: function(opt_triggeringEvent) {
ensureRipple: function(optTriggeringEvent) {
if (!this.hasRipple()) {
this._ripple = this._createRipple();
this._ripple.noink = this.noink;
var rippleContainer = this._rippleContainer || this.root;
if (rippleContainer) {
Polymer.dom(rippleContainer).appendChild(this._ripple);
}
var domContainer = rippleContainer === this.shadyRoot ? this :
rippleContainer;
if (opt_triggeringEvent) {
var target = opt_triggeringEvent.target;
if (domContainer.contains(/** @type {Node} */(target))) {
this._ripple.uiDownAction(opt_triggeringEvent);
if (optTriggeringEvent) {
// Check if the event happened inside of the ripple container
// Fall back to host instead of the root because distributed text
// nodes are not valid event targets
var domContainer = Polymer.dom(this._rippleContainer || this);
var target = Polymer.dom(optTriggeringEvent).rootTarget;
if (domContainer.deepContains( /** @type {Node} */(target))) {
this._ripple.uiDownAction(optTriggeringEvent);
}
}
}
Expand Down
257 changes: 255 additions & 2 deletions test/paper-ripple-behavior.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@

<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../web-component-tester/browser.js"></script>
<script src="../../test-fixture/test-fixture-mocha.js"></script>
<script src="../../iron-test-helpers/mock-interactions.js"></script>

<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../../test-fixture/test-fixture.html">
<link rel="import" href="../../iron-behaviors/iron-button-state.html">
<link rel="import" href="../paper-ripple-behavior.html">
<link rel="import" href="shadowed-ripple.html">
</head>
<body>

Expand All @@ -48,6 +47,26 @@
</template>
</test-fixture>

<test-fixture id="ShadowBasic">
<template>
<sd-ripple></sd-ripple>
</template>
</test-fixture>

<test-fixture id="ShadowText">
<template>
<sd-ripple>Howdy!</sd-ripple>
</template>
</test-fixture>

<test-fixture id="ShadowElement">
<template>
<sd-ripple>
<div id="source">source!</div>
</sd-ripple>
</template>
</test-fixture>

<script>
suite('PaperRippleBehavior', function() {
var ripple;
Expand Down Expand Up @@ -75,6 +94,240 @@
MockInteractions.up(ripple);
});

suite('Correct Targeting', function() {

function assertInteractionCausesRipple(host, node, expected, msg) {
var ripple = host.getRipple();
Polymer.dom.flush();
MockInteractions.down(node);
assert.equal(ripple.ripples.length > 0, expected, msg);
MockInteractions.up(node);
}

function assertInteractionAtLocationCausesRipple(host, node, location, expected, msg) {
var ripple = host.getRipple();
Polymer.dom.flush();
MockInteractions.down(node, location);
assert.equal(ripple.ripples.length > 0, expected, msg);
MockInteractions.up(node);
}

suite('basic', function() {
suite('container = host', function() {

setup(function() {
ripple = fixture('ShadowBasic');
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, true, 'ripple');
});
test('tap #wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});
test('tap #separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});
});

suite('container = wrapper', function() {

setup(function() {
ripple = fixture('ShadowBasic');
ripple._rippleContainer = ripple.$.wrapper;
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap #wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});

test('tap #separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, false, '#separate')
});
});

suite('container = separate', function(done) {

setup(function() {
ripple = fixture('ShadowBasic');
ripple._rippleContainer = ripple.$.separate;
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, false, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});
});
});

suite('distributed text', function() {
var textLocation;

function getTextLocation(ripple) {
// build a Range to get the BCR of a given text node
var r = document.createRange();
r.selectNode(Polymer.dom(ripple.$.content).getDistributedNodes()[0]);
return MockInteractions.middleOfNode(r);
}

suite('container = host', function() {
setup(function() {
ripple = fixture('ShadowText');
textLocation = getTextLocation(ripple);
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, true, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});

test('tap text', function() {
assertInteractionAtLocationCausesRipple(ripple, ripple.$.wrapper, textLocation, true, 'text');
});
});

suite('container = wrapper', function() {
setup(function() {
ripple = fixture('ShadowText');
ripple._rippleContainer = ripple.$.wrapper;
textLocation = getTextLocation(ripple);
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, false, '#separate')
});

test('tap text', function() {
assertInteractionAtLocationCausesRipple(ripple, ripple.$.wrapper, textLocation, true, 'text');
});
});

suite('container = separate', function() {
setup(function() {
ripple = fixture('ShadowText');
ripple._rippleContainer = ripple.$.separate;
textLocation = getTextLocation(ripple);
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, false, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});

test('tap text', function() {
assertInteractionAtLocationCausesRipple(ripple, ripple.$.wrapper, textLocation, false, 'text');
});
});
});

suite('distributed element', function() {
var source;

suite('container = host', function() {
setup(function() {
ripple = fixture('ShadowElement');
source = Polymer.dom(ripple).querySelector('#source');
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, true, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});

test('tap source', function() {
assertInteractionCausesRipple(ripple, source, true, '#source');
});
});

suite('container = wrapper', function() {
setup(function() {
ripple = fixture('ShadowElement');
ripple._rippleContainer = ripple.$.wrapper;
source = Polymer.dom(ripple).querySelector('#source');
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, true, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, false, '#separate')
});

test('tap source', function() {
assertInteractionCausesRipple(ripple, source, true, '#source');
});
});

suite('container = separate', function() {
setup(function() {
ripple = fixture('ShadowElement');
ripple._rippleContainer = ripple.$.separate;
source = Polymer.dom(ripple).querySelector('#source');
});

test('tap host', function() {
assertInteractionCausesRipple(ripple, ripple, false, 'ripple');
});

test('tap wrapper', function() {
assertInteractionCausesRipple(ripple, ripple.$.wrapper, false, '#wrapper');
});

test('tap separate', function() {
assertInteractionCausesRipple(ripple, ripple.$.separate, true, '#separate')
});

test('tap source', function() {
assertInteractionCausesRipple(ripple, source, false, '#source');
});
});
});
});
});
</script>

Expand Down
55 changes: 55 additions & 0 deletions test/shadowed-ripple.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../../iron-behaviors/iron-button-state.html">
<link rel="import" href="../paper-ripple-behavior.html">
<dom-module id="sd-ripple">
<template>
<style>
:host {
display: block;
width: 200px;
}
#separate, #wrapper {
height: 50px;
}
#separate {
background: blue;
}
#wrapper {
background: red;
}
#wrapper > ::content #source {
height: 25px;
width: 50px;
background: green;
}
</style>
<div id="separate">
<div id="target">
Internal Text Node
</div>
</div>
<div id="wrapper">
<content id="content"></content>
</div>
</template>
<script>
Polymer({
is: 'sd-ripple',
behaviors: [
Polymer.IronButtonState,
Polymer.IronControlState,
Polymer.PaperRippleBehavior
]
});
</script>
</dom-module>

0 comments on commit 4b244a5

Please sign in to comment.