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

Effective children #2548

Merged
merged 24 commits into from
Oct 14, 2015
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f34fb45
Adds `getEffectiveChildNodes`, `getEffectiveChildren`, `getEffectiveT…
Aug 3, 2015
6499e83
Adds `Polymer.dom(element).observeChildren(callback)` api
Aug 4, 2015
1ca065f
Merge branch 'master' into effective-children
Aug 10, 2015
effedcb
Factor dom-api's into separate helpers.
Aug 10, 2015
393ba40
Merge branch 'master' into effective-children
Aug 11, 2015
b11f86b
Add mutation tracking for distributedNodes.
Aug 13, 2015
07261e4
Add `Polymer.dom().notifyObservers` method to 'kick' observers, for e…
Aug 13, 2015
65abbd0
Merge branch 'master' into effective-children
Aug 13, 2015
19aa6eb
Merge branch 'master' into effective-children
Aug 20, 2015
1774f57
Merge branch 'master' into effective-children
Aug 24, 2015
8242a98
Add optional attribute tracking to support better distributed node no…
Aug 25, 2015
4099342
Merge branch 'master' into effective-children
Aug 27, 2015
ff2c088
Merge branch 'master' into effective-children
Aug 27, 2015
c09296e
Merge branch 'master' into effective-children
Aug 31, 2015
bd90b57
add `observeNodes` tests.
Sep 1, 2015
9ff2ee4
make tests work on polyfill.
Sep 1, 2015
b40060a
Merge branch 'master' into effective-children
Oct 8, 2015
d021039
Merge branch 'master' into effective-children
Oct 9, 2015
669acaa
Simplify change tracking by always dirty checking at the observer lev…
Oct 13, 2015
e11a4f3
Merge branch 'master' into effective-children
Oct 13, 2015
54911a7
Make shadow attribute tracking automatic based on detecting a <conten…
Oct 13, 2015
0ede79a
Add docs
Oct 13, 2015
8b1face
Add <content>.getDistributedNodes observation. Refactor flush.
Oct 14, 2015
344f5cc
ensure distribution observers see all changes that can come from attr…
Oct 14, 2015
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
54 changes: 54 additions & 0 deletions src/lib/dom-api-classlist.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!--
@license
Copyright (c) 2014 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
-->
<script>

(function() {
'use strict';

var DomApi = Polymer.DomApi.ctor;

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();
},
contains: function() {
return this.node.classList.contains.apply(this.node.classList,
arguments);
}
}

})();
</script>
93 changes: 93 additions & 0 deletions src/lib/dom-api-event.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<!--
@license
Copyright (c) 2014 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="settings.html">
<script>
Polymer.EventApi = (function() {
'use strict';

var DomApi = Polymer.DomApi.ctor;
var Settings = Polymer.Settings;

DomApi.Event = function(event) {
this.event = event;
};

if (Settings.useShadow) {

DomApi.Event.prototype = {

get rootTarget() {
return this.event.path[0];
},

get localTarget() {
return this.event.target;
},

get path() {
return this.event.path;
}

};

} else {

DomApi.Event.prototype = {

get rootTarget() {
return this.event.target;
},

get localTarget() {
var current = this.event.currentTarget;
var currentRoot = current && Polymer.dom(current).getOwnerRoot();
var p$ = this.path;
for (var i=0; i < p$.length; i++) {
if (Polymer.dom(p$[i]).getOwnerRoot() === currentRoot) {
return p$[i];
}
}
},

// TODO(sorvell): simulate event.path. This probably incorrect for
// non-bubbling events.
get path() {
if (!this.event._path) {
var path = [];
var o = this.rootTarget;
while (o) {
path.push(o);
o = Polymer.dom(o).parentNode || o.host;
}
// event path includes window in most recent native implementations
path.push(window);
this.event._path = path;
}
return this.event._path;
}

};

}

var factory = function(event) {
if (!event.__eventApi) {
event.__eventApi = new DomApi.Event(event);
}
return event.__eventApi;
};

return {
factory: factory
};

})();

</script>
88 changes: 88 additions & 0 deletions src/lib/dom-api-flush.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!--
@license
Copyright (c) 2014 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
-->
<script>

// add Polymer.dom flush api...
Polymer.Base.extend(Polymer.dom, {

_flushGuard: 0,
_FLUSH_MAX: 100,
_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
_debouncers: [],
_preFlushList: [],
_finishDebouncer: null,

// flush and debounce exposed as statics on Polymer.dom
flush: function() {
for (var i=0; i < this._preFlushList.length; i++) {
this._preFlushList[i]();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move _preFlush into _flush so it loops?

}
this._flush();
},

_flush: function() {
// flush debouncers
for (var i=0; i < this._debouncers.length; i++) {
this._debouncers[i].complete();
}
// clear the list of debouncers
if (this._finishDebouncer) {
this._finishDebouncer.complete();
}
// again make any pending CE mutations that might trigger debouncer
// additions go...
this._flushPolyfills();
// flush again if there are now any debouncers to process
if (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
this._flushGuard++;
this._flush();
} else {
if (this._flushGuard >= this._FLUSH_MAX) {
console.warn('Polymer.dom.flush aborted. Flush may not be complete.')
}
this._flushGuard = 0;
}
},

// TODO(sorvell): There is currently not a good way
// to process all custom elements mutations under SD polyfill because
// these mutations may be inside shadowRoots.
_flushPolyfills: function() {
if (this._needsTakeRecords) {
CustomElements.takeRecords();
}
},

addPreflush: function(fn) {
this._preFlushList.push(fn);
},

// TODO(sorvell): Map when we can?
removePreflush: function(fn) {
var i = this._preFlushList.indexOf(fn);
if (i >= 0) {
this._preFlushList.splice(i, 1);
}
},

addDebouncer: function(debouncer) {
this._debouncers.push(debouncer);
// ensure the list of active debouncers is cleared when done.
this._finishDebouncer = Polymer.Debounce(this._finishDebouncer,
this._finishFlush);
},

_finishFlush: function() {
Polymer.dom._debouncers = [];
}

});

</script>
111 changes: 111 additions & 0 deletions src/lib/dom-api-mutation-content.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<!--
@license
Copyright (c) 2014 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="settings.html">
<script>
(function() {
'use strict';

var DomApi = Polymer.DomApi.ctor;
var Settings = Polymer.Settings;

DomApi.MutationContent = function(domApi) {
DomApi.Mutation.call(this, domApi);
};

DomApi.MutationContent.prototype = Object.create(DomApi.Mutation.prototype);

Polymer.Base.extend(DomApi.MutationContent.prototype, {

addListener: function(callback, options) {
var h = DomApi.Mutation.prototype.addListener.call(this, callback,
options);
this._scheduleNotify();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super does notifyInitial (no-op since childNodes is empty).

Dirty check approach seems broken for initial? Consider simplifying initial by constraining when you can observe?

return h;
},

_ensureSetup: function(options) {},

notify: function() {
if (this._hasListeners()) {
this._scheduleNotify();
}
},

_notify: function() {
var info = this._suspendChangeInfo ? {} : this._calcChanges();
if (info) {
info.target = this.node;
this._callListeners(info);
}
},

_calcChanges: function() {
var changes = {
addedNodes: [],
removedNodes: []
};
var o$ = this.node.__distributedNodes = this.node.__distributedNodes ||
[];
var n$ = this.domApi.getDistributedNodes();
this.node.__distributedNodes = n$;
var splices = Polymer.ArraySplice.calculateSplices(n$, o$);
// process removals
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
changes.removedNodes.push(n);
}
}
// process adds
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
for (var j=s.index; j < s.index + s.addedCount; j++) {
changes.addedNodes.push(n$[j]);
}
}
if (changes.addedNodes.length || changes.removedNodes.length) {
return changes;
}
}

});

if (Settings.useShadow) {

Polymer.Base.extend(DomApi.MutationContent.prototype, {

_ensureSetup: function(options) {
this._trackAttributes = this._trackAttributes ||
options.attributes;
if (!this._observer) {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
this._observer = Polymer.dom(host).observeNodes(
this.notify.bind(this), {attributes: this._trackAttributes});
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will not recurse back up with attributes:true if was called previously with attributes:false, since ensureSetup is 1-shot

}
},

_ensureCleanup: function() {
if (this._observer) {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
Polymer.dom(host).unobserveNodes(this._observer);
}
}
}

});

}

})();

</script>
Loading