Skip to content

Commit b11f86b

Browse files
author
Steven Orvell
committed
Add mutation tracking for distributedNodes.
1 parent 393ba40 commit b11f86b

8 files changed

+413
-223
lines changed

src/lib/dom-api-flush.html

+21-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@
1616
_FLUSH_MAX: 100,
1717
_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
1818
_debouncers: [],
19+
_preFlushList: [],
1920
_finishDebouncer: null,
2021

2122
// flush and debounce exposed as statics on Polymer.dom
2223
flush: function() {
24+
for (var i=0; i < this._preFlushList.length; i++) {
25+
this._preFlushList[i]();
26+
}
27+
this._flush();
28+
},
29+
30+
_flush: function() {
2331
// flush debouncers
2432
for (var i=0; i < this._debouncers.length; i++) {
2533
this._debouncers[i].complete();
@@ -34,7 +42,7 @@
3442
// flush again if there are now any debouncers to process
3543
if (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
3644
this._flushGuard++;
37-
this.flush();
45+
this._flush();
3846
} else {
3947
if (this._flushGuard >= this._FLUSH_MAX) {
4048
console.warn('Polymer.dom.flush aborted. Flush may not be complete.')
@@ -52,6 +60,18 @@
5260
}
5361
},
5462

63+
addPreflush: function(fn) {
64+
this._preFlushList.push(fn);
65+
},
66+
67+
// TODO(sorvell): Map when we can?
68+
removePreflush: function(fn) {
69+
var i = this._preFlushList.indexOf(fn);
70+
if (i >= 0) {
71+
this._preFlushList.splice(i, 1);
72+
}
73+
},
74+
5575
addDebouncer: function(debouncer) {
5676
this._debouncers.push(debouncer);
5777
// ensure the list of active debouncers is cleared when done.

src/lib/dom-api-mutation-content.html

+72-100
Original file line numberDiff line numberDiff line change
@@ -15,113 +15,85 @@
1515
var DomApi = Polymer.DomApi.ctor;
1616
var Settings = Polymer.Settings;
1717

18-
DomApi.prototype.observeDistributedNodes = function(callback) {
19-
if (!this._observer) {
20-
this._observer = new DomApi.Mutation(this);
21-
}
22-
return this._observer.addObserver(callback);
23-
};
24-
25-
DomApi.prototype.unobserveDistributedNodes = function(handle) {
26-
if (this._observer) {
27-
this._observer.removeObserver(handle);
28-
}
29-
}
30-
3118
DomApi.MutationContent = function(domApi) {
32-
this.domApi = domApi;
33-
this.node = this.domApi.node;
34-
this._observers = [];
35-
this._addedNodes = [];
36-
this._removedNodes = [];
19+
DomApi.Mutation.call(this, domApi);
3720
};
3821

39-
DomApi.MutationContent.prototype = {
40-
41-
// addObserver: function(callback) {
42-
// return this._observers.push(callback);
43-
// },
44-
45-
// removeObserver: function(handle) {
46-
// this._observers.splice(handle - 1, 1);
47-
// },
48-
49-
// hasObservers: function() {
50-
// return Boolean(this._observers.length);
51-
// },
52-
53-
// _scheduleMutationNotify: function() {
54-
// this._mutationDebouncer = Polymer.Debounce(this._mutationDebouncer,
55-
// this._notifyObservers);
56-
// this._mutationDebouncer.context = this;
57-
// Polymer.dom.addDebouncer(this._mutationDebouncer);
58-
// },
59-
60-
// _notifyObservers: function(mxns) {
61-
// var info = {
62-
// target: this.node,
63-
// addedNodes: this._addedNodes,
64-
// removedNodes: this._removedNodes
65-
// }
66-
// var o$ = this._observers;
67-
// for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) {
68-
// o.call(null, info);
69-
// }
70-
// this._addedNodes = [];
71-
// this._removedNodes = [];
72-
// }
73-
74-
// observeDistributedNodes: function(callback) {
75-
// if (this.node.localName !== 'content') {
76-
// console.warn('Must call `observeDistributedNodes` on a <content> element.');
77-
// return;
78-
// }
79-
// // setup <content>.getDistributedNodes observation
80-
// if (!this.hasObservers()) {
81-
// this._startObserveDistributedNodes();
82-
// }
83-
// this._addObserver(callback);
84-
// },
85-
86-
// unobserveDistributedNodes: function(handle) {
87-
// if (this.node.localName !== 'content') {
88-
// return;
89-
// }
90-
// this._removeObserver(handle);
91-
// if (!this.hasObservers()) {
92-
// this._stopObservingDistributedNodes();
93-
// }
94-
// },
95-
96-
// _startObservingDistributedNodes: function() {
97-
// this._distributedObservers = [];
98-
// var root = this.getOwnerRoot();
99-
// var host = root && root.host;
100-
// if (host) {
101-
// var h = Polymer.dom(host)
102-
// .observeChildren(this._scheduleDistributedNodesNotify);
103-
// this._distributedObservers.push(h);
104-
// }
105-
// },
106-
107-
// _stopObservingDistributedNodes: function() {
108-
109-
// },
110-
111-
// _scheduleDistributedNodesNotify: function() {
112-
// this._distributedNodesDebouncer =
113-
// Polymer.Debounce(this._distributedNodesDebouncer,
114-
// this._notifyObservers);
115-
// this._distributedNodesDebouncer.context = this.node;
116-
// Polymer.dom.addDebouncer(this._distributedNodesDebouncer);
117-
// },
22+
DomApi.MutationContent.prototype = Object.create(DomApi.Mutation.prototype);
23+
24+
Polymer.Base.extend(DomApi.MutationContent.prototype, {
25+
26+
addListener: function(callback, includeChanges) {
27+
this._includeChanges = includeChanges;
28+
var h = DomApi.Mutation.prototype.addListener.call(this, callback);
29+
this._scheduleNotify();
30+
return h;
31+
},
32+
33+
notifyIfNeeded: function() {
34+
if (this._hasListeners()) {
35+
this._scheduleNotify();
36+
}
37+
},
38+
39+
_notify: function() {
40+
var info = this._includeChanges ? this._calcChanges() : {};
41+
if (info) {
42+
info.target = this.node;
43+
this._callListeners(info);
44+
}
45+
},
46+
47+
_calcChanges: function() {
48+
var changes = {
49+
addedNodes: [],
50+
removedNodes: []
51+
};
52+
var o$ = this.node.__distributedNodes = this.node.__distributedNodes ||
53+
[];
54+
var n$ = this.domApi.getDistributedNodes();
55+
this.node.__distributedNodes = n$;
56+
var splices = Polymer.ArraySplice.calculateSplices(n$, o$);
57+
// process removals
58+
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
59+
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
60+
changes.removedNodes.push(n);
61+
}
62+
}
63+
// process adds
64+
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
65+
for (var j=s.index; j < s.index + s.addedCount; j++) {
66+
changes.addedNodes.push(n$[j]);
67+
}
68+
}
69+
if (changes.addedNodes.length || changes.removedNodes.length) {
70+
return changes;
71+
}
72+
}
11873

119-
};
74+
});
12075

12176
if (Settings.useShadow) {
122-
77+
78+
Polymer.Base.extend(DomApi.MutationContent.prototype, {
79+
80+
_ensureObserver: function() {
81+
var root = this.domApi.getOwnerRoot();
82+
var host = root && root.host;
83+
if (host) {
84+
this._observer = Polymer.dom(host).observeNodes(
85+
this.notifyIfNeeded.bind(this));
86+
}
87+
},
88+
89+
_cleanupObserver: function() {
90+
if (this._observer) {
91+
Polymer.dom(host).unobserveNodes(this._observer);
92+
}
93+
}
94+
95+
});
12396

124-
12597
}
12698

12799
})();

0 commit comments

Comments
 (0)