Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.8 shady api #1508

Merged
merged 8 commits into from
May 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/lib/dom-api.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<script>

Polymer.DomApi = (function() {
'use strict';

var Settings = Polymer.Settings;
var getInnerHTML = Polymer.domInnerHTML.getInnerHTML;
Expand Down Expand Up @@ -365,10 +366,58 @@
while (this.childNodes.length) {
this.removeChild(this.childNodes[0]);
}
},

setAttribute: function(name, value) {
this.node.setAttribute(name, value);
this._distributeParent();
},

removeAttribute: function(name) {
this.node.removeAttribute(name);
this._distributeParent();
},

_distributeParent: function() {
if (this.parentNode && this.parentNode.shadyRoot) {
this._lazyDistribute(this.parentNode);
}
}

};

Object.defineProperty(DomApi.prototype, 'classList', {
get: function() {
if (!this._classList) {
this._classList = new DomApi.ClassList(this);
}
return this._classList;
},
configurable: true
});

DomApi.ClassList = function(host) {
this.domApi = host;
this.node = host.node;
}

DomApi.ClassList.prototype = {
add: function() {
this.node.classList.add.apply(this.node.classList, arguments);
this.domApi._distributeParent();
},

remove: function() {
this.node.classList.remove.apply(this.node.classList, arguments);
this.domApi._distributeParent();
},

toggle: function() {
this.node.classList.toggle.apply(this.node.classList, arguments);
this.domApi._distributeParent();
}
}

// changes and accessors...
if (!Settings.useShadow) {

Expand Down Expand Up @@ -517,6 +566,7 @@
return getInnerHTML(this.node, true);
};


} else {

DomApi.prototype.querySelectorAll = function(selector) {
Expand All @@ -543,6 +593,8 @@
return n$ ? Array.prototype.slice.call(n$) : [];
};

DomApi.prototype._distributeParent = function() {}

Object.defineProperties(DomApi.prototype, {

childNodes: {
Expand Down
77 changes: 60 additions & 17 deletions src/mini/shady.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,18 @@
* Force this element to distribute its children to its local dom.
* A user should call `distributeContent` if distribution has been
* invalidated due to changes to selectors on child elements that
* effect distribution. For example, if an element contains an
* insertion point with <content select=".foo"> and a `foo` class is
* added to a child, then `distributeContent` must be called to update
* effect distribution that were not made via `Polymer.dom`.
* For example, if an element contains an insertion point with
* <content select=".foo"> and a `foo` class is added to a child,
* then `distributeContent` must be called to update
* local dom distribution.
*/
distributeContent: function() {
if (this._useContent) {
this.shadyRoot._distributionClean = false;
this._distributeContent();
if (this.shadyRoot) {
// Distribute the host that's the top of this element's distribution
// tree. Distributing that host will *always* distibute this element.
var host = getTopDistributingHost(this);
Polymer.dom(this)._lazyDistribute(host);
}
},

Expand Down Expand Up @@ -151,6 +154,9 @@
if (child._destinationInsertionPoints) {
child._destinationInsertionPoints = undefined;
}
if (isInsertionPoint(child)) {
clearDistributedDestinationInsertionPoints(child);
}
}
// insertion points
var root = this.shadyRoot;
Expand Down Expand Up @@ -183,6 +189,10 @@
var p$ = node._insertionPoints;
for (var i=0, l=p$.length, p; (i<l) && (p=p$[i]); i++) {
this._distributeInsertionPoint(p, pool);
// provoke redistribution on insertion point parents
// must do this on all candidate hosts since distribution in this
// scope invalidates their distribution.
maybeRedistributeParent(p, this);
}
},

Expand All @@ -202,13 +212,6 @@
pool[i] = undefined;
// since at least one node matched, we won't need fallback content
anyDistributed = true;
var parent = content.lightParent;
// dirty a shadyRoot if a change may trigger reprojection!
if (parent && parent.shadyRoot &&
hasInsertionPoint(parent.shadyRoot)) {
parent.shadyRoot._distributionClean = false;
this.shadyRoot._dirtyRoots.push(parent);
}
}
}
// Fallback content if nothing was distributed here
Expand Down Expand Up @@ -328,14 +331,33 @@
var points = child._destinationInsertionPoints;
if (!points) {
child._destinationInsertionPoints = [insertionPoint];
// TODO(sorvell): _destinationInsertionPoints may not be cleared when
// nodes are dynamically added/removed, therefore test before adding
// insertion points.
} else if (points.indexOf(insertionPoint) < 0) {
} else {
points.push(insertionPoint);
}
}

function clearDistributedDestinationInsertionPoints(content) {
var e$ = content._distributedNodes;
for (var i=0; i < e$.length; i++) {
var d = e$[i]._destinationInsertionPoints;
if (d) {
// this is +1 because these insertion points are *not* in this scope
d.splice(d.indexOf(content)+1, d.length);
}
}
}

// dirty a shadyRoot if a change may trigger reprojection!
function maybeRedistributeParent(content, host) {
var parent = content.lightParent;
if (parent && parent.shadyRoot &&
hasInsertionPoint(parent.shadyRoot) &&
parent.shadyRoot._distributionClean) {
parent.shadyRoot._distributionClean = false;
host.shadyRoot._dirtyRoots.push(parent);
}
}

function isFinalDestination(insertionPoint, node) {
var points = node._destinationInsertionPoints;
return points && points[points.length - 1] === insertionPoint;
Expand Down Expand Up @@ -379,6 +401,27 @@
function getComposedParent(node) {
return node.__patched ? node._composedParent : node.parentNode;
}

// returns the host that's the top of this host's distribution tree
function getTopDistributingHost(host) {
while (host && hostNeedsRedistribution(host)) {
host = host.domHost;
}
return host;
}

// Return true if a host's children includes
// an insertion point that selects selectively
function hostNeedsRedistribution(host) {
var c$ = Polymer.dom(host).children;
for (var i=0, c; i < c$.length; i++) {
c = c$[i];
if (c.localName === 'content') {
return host.domHost;
}
}
}

})();

</script>
16 changes: 8 additions & 8 deletions src/standard/utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
bool = !node.classList.contains(name);
}
if (bool) {
node.classList.add(name);
Polymer.dom(node).classList.add(name);
} else {
node.classList.remove(name);
Polymer.dom(node).classList.remove(name);
}
},

Expand All @@ -55,9 +55,9 @@
bool = !node.hasAttribute(name);
}
if (bool) {
node.setAttribute(name, '');
Polymer.dom(node).setAttribute(name, '');
} else {
node.removeAttribute(name);
Polymer.dom(node).removeAttribute(name);
}
},

Expand All @@ -71,10 +71,10 @@
*/
classFollows: function(name, toElement, fromElement) {
if (fromElement) {
fromElement.classList.remove(name);
Polymer.dom(fromElement).classList.remove(name);
}
if (toElement) {
toElement.classList.add(name);
Polymer.dom(toElement).classList.add(name);
}
},

Expand All @@ -88,10 +88,10 @@
*/
attributeFollows: function(name, toElement, fromElement) {
if (fromElement) {
fromElement.removeAttribute(name);
Polymer.dom(fromElement).removeAttribute(name);
}
if (toElement) {
toElement.setAttribute(name, '');
Polymer.dom(toElement).setAttribute(name, '');
}
},

Expand Down
125 changes: 125 additions & 0 deletions test/smoke/nested-ip.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!doctype html>
<html>
<head>
<title>polymer</title>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../polymer.html">
</head>
<body>

<x-outer></x-outer>

<dom-module id="x-outer">
<template>
<!-- <template is="dom-repeat" items="{{items}}"><div item>{{item}}</div></template> -->
<x-inner><div item>A</div><div item>B</div><div item>C</div></x-inner>
</template>
</dom-module>

<dom-module id="x-inner">
<style>
.one, .two {
display: block;
border: 2px solid orange;
margin: 10px;
padding: 10px;
}

.two {
border-color: green;
}
</style>
<template>
<x-inner-most class="one"><content class="item" select="[item]"></content></x-inner-most>

<x-inner-most class="two"><content class="notItem" select=":not([item])"></content></x-inner-most>
</template>
</dom-module>

<dom-module id="x-inner-most">
<template>
<div style="background-color: green;">
<content class="test" select="[test]"></content>
</div>
<div style="background-color: red;">
<content class="notTest" select=":not([test])"></content>
</div>
<br>
<button on-click="_onTest1a">[test]:not[item]</button>
<button on-click="_onTest2a">:not[test][item]</button>
<button on-click="_onTest1b">auto: [test]:not[item]</button>
<button on-click="_onTest2b">auto: :not[test][item]</button>
</template>
</dom-module>

<script>
(function() {
HTMLImports.whenReady(function() {
Polymer({
is: 'x-outer',
properties: {
items: {
type: Array,
value: ["A", "B", "C"]
}
}
});

Polymer({
is: 'x-inner'
});

var element;

Polymer({
is: 'x-inner-most',

_onTest1a: function() {
this.doTest(function(e) {
e.setAttribute('test', '');
e.removeAttribute('item');
this.distributeContent();
});
},

_onTest1b: function() {
this.doTest(function(e) {
Polymer.dom(e).setAttribute('test', '');
Polymer.dom(e).removeAttribute('item');
});
},

_onTest2a: function() {
this.doTest(function(e) {
e.setAttribute('item', '');
e.removeAttribute('test');
this.distributeContent();
});
},

_onTest2b: function() {
this.doTest(function(e) {
Polymer.dom(e).setAttribute('item', '');
Polymer.dom(e).removeAttribute('test');
});
},

doTest: function(work) {
element = element || document.querySelector("[item]");
console.group('test');
console.log('before', Polymer.dom(element).getDestinationInsertionPoints());
//
work.call(this, element);
Polymer.dom.flush();
//
console.log('after', Polymer.dom(element).getDestinationInsertionPoints());
console.groupEnd('test');
}
});
});

})();
</script>

</body>
</html>
Loading