intersection-observer 0.4.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/intersection-observer-test.js +24 -0
- package/intersection-observer.js +38 -14
- package/package.json +1 -1
package/README.md
CHANGED
@@ -4,6 +4,7 @@ This library polyfills the native [`IntersectionObserver`](http://w3c.github.io/
|
|
4
4
|
|
5
5
|
- [Installation](#installation)
|
6
6
|
- [Configuring the polyfill](#configuring-the-polyfill)
|
7
|
+
- [Limitations](#limitations)
|
7
8
|
- [Browser support](#browser-support)
|
8
9
|
- [Running the tests](#running-the-tests)
|
9
10
|
|
@@ -81,6 +82,26 @@ io.observe(someTargetElement);
|
|
81
82
|
|
82
83
|
**Note:** the `POLL_INTERVAL` property must be set prior to calling the `.observe` method, or the default configuration will be used.
|
83
84
|
|
85
|
+
**Ignoring DOM changes**
|
86
|
+
|
87
|
+
You can also choose to not check for intersections when the DOM changes by setting an observer's `USE_MUTATION_OBSERVER` property to `false` (either globally on the prototype or per-instance)
|
88
|
+
|
89
|
+
```js
|
90
|
+
IntersectionObserver.prototype.USE_MUTATION_OBSERVER = false; // Globally
|
91
|
+
|
92
|
+
// for an instance
|
93
|
+
var io = new IntersectionObserver(callback);
|
94
|
+
io.USE_MUTATION_OBSERVER = false;
|
95
|
+
```
|
96
|
+
|
97
|
+
This is recommended in cases where the DOM will update frequently but you know those updates will have no affect on the position or your target elements.
|
98
|
+
|
99
|
+
## Limitations
|
100
|
+
|
101
|
+
This polyfill does not attempt to report intersections across same-origin `iframe` boundaries. While supporting same-origin iframes is technically possible, it would drastically reduce performance. Since most `iframe` usage on the web is cross-origin, this polyfill chooses to optimize for performantly handling the most common use cases. (Note: neither this polyfill nor native implementations support reporting intersections across cross-origin `iframe` boundaries.)
|
102
|
+
|
103
|
+
This polyfill also does not support the [proposed v2 additions](https://github.com/szager-chromium/IntersectionObserver/blob/v2/explainer.md), as these features are not currently possible to do with JavaScript and existing web APIs.
|
104
|
+
|
84
105
|
## Browser support
|
85
106
|
|
86
107
|
The polyfill has been tested and known to work in the latest version of all browsers.
|
@@ -724,6 +724,30 @@ describe('IntersectionObserver', function() {
|
|
724
724
|
|
725
725
|
io.observe(targetEl1);
|
726
726
|
});
|
727
|
+
|
728
|
+
it('handles roots in shadow DOM', function(done) {
|
729
|
+
var shadowRoot = grandParentEl.attachShadow({mode: 'open'});
|
730
|
+
|
731
|
+
shadowRoot.innerHTML =
|
732
|
+
'<style>' +
|
733
|
+
'#slot-parent {' +
|
734
|
+
' position: relative;' +
|
735
|
+
' width: 400px;' +
|
736
|
+
' height: 200px;' +
|
737
|
+
'}' +
|
738
|
+
'</style>' +
|
739
|
+
'<div id="slot-parent"><slot></slot></div>';
|
740
|
+
|
741
|
+
var slotParent = shadowRoot.getElementById('slot-parent');
|
742
|
+
|
743
|
+
io = new IntersectionObserver(function(records) {
|
744
|
+
expect(records.length).to.be(1);
|
745
|
+
expect(records[0].intersectionRatio).to.be(1);
|
746
|
+
done();
|
747
|
+
}, {root: slotParent});
|
748
|
+
|
749
|
+
io.observe(targetEl1);
|
750
|
+
});
|
727
751
|
}
|
728
752
|
|
729
753
|
|
package/intersection-observer.js
CHANGED
@@ -4,14 +4,17 @@
|
|
4
4
|
* Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
|
5
5
|
*
|
6
6
|
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
7
|
-
*
|
7
|
+
*
|
8
8
|
*/
|
9
|
-
|
10
|
-
(function(window, document) {
|
9
|
+
(function() {
|
11
10
|
'use strict';
|
12
11
|
|
12
|
+
// Exit early if we're not running in a browser.
|
13
|
+
if (typeof window !== 'object') {
|
14
|
+
return;
|
15
|
+
}
|
13
16
|
|
14
|
-
//
|
17
|
+
// Exit early if all IntersectionObserver and IntersectionObserverEntry
|
15
18
|
// features are natively supported.
|
16
19
|
if ('IntersectionObserver' in window &&
|
17
20
|
'IntersectionObserverEntry' in window &&
|
@@ -31,9 +34,15 @@ if ('IntersectionObserver' in window &&
|
|
31
34
|
}
|
32
35
|
|
33
36
|
|
37
|
+
/**
|
38
|
+
* A local reference to the document.
|
39
|
+
*/
|
40
|
+
var document = window.document;
|
41
|
+
|
42
|
+
|
34
43
|
/**
|
35
44
|
* An IntersectionObserver registry. This registry exists to hold a strong
|
36
|
-
* reference to IntersectionObserver instances currently
|
45
|
+
* reference to IntersectionObserver instances currently observing a target
|
37
46
|
* element. Without this registry, instances without another reference may be
|
38
47
|
* garbage collected.
|
39
48
|
*/
|
@@ -62,7 +71,9 @@ function IntersectionObserverEntry(entry) {
|
|
62
71
|
|
63
72
|
// Sets intersection ratio.
|
64
73
|
if (targetArea) {
|
65
|
-
|
74
|
+
// Round the intersection ratio to avoid floating point math issues:
|
75
|
+
// https://github.com/w3c/IntersectionObserver/issues/324
|
76
|
+
this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
|
66
77
|
} else {
|
67
78
|
// If area is zero and is intersecting, sets to 1, otherwise to 0
|
68
79
|
this.intersectionRatio = this.isIntersecting ? 1 : 0;
|
@@ -124,6 +135,12 @@ IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;
|
|
124
135
|
*/
|
125
136
|
IntersectionObserver.prototype.POLL_INTERVAL = null;
|
126
137
|
|
138
|
+
/**
|
139
|
+
* Use a mutation observer on the root element
|
140
|
+
* to detect intersection changes.
|
141
|
+
*/
|
142
|
+
IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;
|
143
|
+
|
127
144
|
|
128
145
|
/**
|
129
146
|
* Starts observing a target element for intersection changes based on
|
@@ -131,10 +148,11 @@ IntersectionObserver.prototype.POLL_INTERVAL = null;
|
|
131
148
|
* @param {Element} target The DOM element to observe.
|
132
149
|
*/
|
133
150
|
IntersectionObserver.prototype.observe = function(target) {
|
134
|
-
|
135
|
-
if (this._observationTargets.some(function(item) {
|
151
|
+
var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
|
136
152
|
return item.element == target;
|
137
|
-
})
|
153
|
+
});
|
154
|
+
|
155
|
+
if (isTargetAlreadyObserved) {
|
138
156
|
return;
|
139
157
|
}
|
140
158
|
|
@@ -243,7 +261,7 @@ IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
|
|
243
261
|
|
244
262
|
/**
|
245
263
|
* Starts polling for intersection changes if the polling is not already
|
246
|
-
* happening, and if the page's
|
264
|
+
* happening, and if the page's visibility state is visible.
|
247
265
|
* @private
|
248
266
|
*/
|
249
267
|
IntersectionObserver.prototype._monitorIntersections = function() {
|
@@ -260,7 +278,7 @@ IntersectionObserver.prototype._monitorIntersections = function() {
|
|
260
278
|
addEvent(window, 'resize', this._checkForIntersections, true);
|
261
279
|
addEvent(document, 'scroll', this._checkForIntersections, true);
|
262
280
|
|
263
|
-
if ('MutationObserver' in window) {
|
281
|
+
if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
|
264
282
|
this._domObserver = new MutationObserver(this._checkForIntersections);
|
265
283
|
this._domObserver.observe(document, {
|
266
284
|
attributes: true,
|
@@ -545,7 +563,7 @@ function now() {
|
|
545
563
|
|
546
564
|
|
547
565
|
/**
|
548
|
-
* Throttles a function and delays its
|
566
|
+
* Throttles a function and delays its execution, so it's only called at most
|
549
567
|
* once within a given time period.
|
550
568
|
* @param {Function} fn The function to throttle.
|
551
569
|
* @param {number} timeout The amount of time that must pass before the
|
@@ -676,7 +694,7 @@ function getEmptyRect() {
|
|
676
694
|
}
|
677
695
|
|
678
696
|
/**
|
679
|
-
* Checks to see if a parent element contains a child
|
697
|
+
* Checks to see if a parent element contains a child element (including inside
|
680
698
|
* shadow DOM).
|
681
699
|
* @param {Node} parent The parent element.
|
682
700
|
* @param {Node} child The child element.
|
@@ -706,6 +724,12 @@ function getParentNode(node) {
|
|
706
724
|
// If the parent is a shadow root, return the host element.
|
707
725
|
return parent.host;
|
708
726
|
}
|
727
|
+
|
728
|
+
if (parent && parent.assignedSlot) {
|
729
|
+
// If the parent is distributed in a <slot>, return the parent of a slot.
|
730
|
+
return parent.assignedSlot.parentNode;
|
731
|
+
}
|
732
|
+
|
709
733
|
return parent;
|
710
734
|
}
|
711
735
|
|
@@ -714,4 +738,4 @@ function getParentNode(node) {
|
|
714
738
|
window.IntersectionObserver = IntersectionObserver;
|
715
739
|
window.IntersectionObserverEntry = IntersectionObserverEntry;
|
716
740
|
|
717
|
-
}(
|
741
|
+
}());
|