intersection-observer 0.4.1 → 0.5.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # `IntersectionObserver` polyfill
2
2
 
3
- This library polyfills the native [`IntersectionObserver`](http://wicg.github.io/IntersectionObserver/) API in unsupporting browsers. See the [API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) for usage information.
3
+ This library polyfills the native [`IntersectionObserver`](http://w3c.github.io/IntersectionObserver/) API in unsupporting browsers. See the [API documentation](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) for usage information.
4
4
 
5
5
  - [Installation](#installation)
6
6
  - [Configuring the polyfill](#configuring-the-polyfill)
@@ -9,7 +9,7 @@ This library polyfills the native [`IntersectionObserver`](http://wicg.github.io
9
9
 
10
10
  ## Installation
11
11
 
12
- You can install the polyfill via npm or by downloading a [zip](https://github.com/WICG/IntersectionObserver/archive/gh-pages.zip) of this repository:
12
+ You can install the polyfill via npm or by downloading a [zip](https://github.com/w3c/IntersectionObserver/archive/gh-pages.zip) of this repository:
13
13
 
14
14
  ```sh
15
15
  npm install intersection-observer
@@ -81,6 +81,20 @@ io.observe(someTargetElement);
81
81
 
82
82
  **Note:** the `POLL_INTERVAL` property must be set prior to calling the `.observe` method, or the default configuration will be used.
83
83
 
84
+ **Ignoring DOM changes**
85
+
86
+ 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)
87
+
88
+ ```js
89
+ IntersectionObserver.prototype.USE_MUTATION_OBSERVER = false; // Globally
90
+
91
+ // for an instance
92
+ var io = new IntersectionObserver(callback);
93
+ io.USE_MUTATION_OBSERVER = false;
94
+ ```
95
+
96
+ 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.
97
+
84
98
  ## Browser support
85
99
 
86
100
  The polyfill has been tested and known to work in the latest version of all browsers.
@@ -0,0 +1,47 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <script>
6
+ // delete window.IntersectionObserver;
7
+ </script>
8
+ <script src="intersection-observer.js"></script>
9
+ <script>
10
+ function init() {
11
+ function callback(entries, observer) {
12
+ Array.prototype.forEach.call(entries, function(entry) {
13
+ if (entry.intersectionRatio > 0) {
14
+ entry.target.classList.add('visible');
15
+ }
16
+ });
17
+ }
18
+ var observer = new IntersectionObserver(callback, { root: document.getElementById('outer') });
19
+ Array.prototype.forEach.call(document.querySelectorAll('#outer div'), function(el) {
20
+ observer.observe(el);
21
+ });
22
+ }
23
+ window.addEventListener('load', init);
24
+ </script>
25
+ <style>
26
+ #outer {
27
+ overflow-y: hidden;
28
+ height: 2em;
29
+ border: 10px solid #0000;
30
+ }
31
+ #outer div {
32
+ height: 100%;
33
+ }
34
+ #el2 {
35
+ background: red;
36
+ }
37
+
38
+ </style>
39
+ </head>
40
+ <body>
41
+ <div id="outer">
42
+ <div id="el1">Element 1</div>
43
+ <div id="el2">Element 2</div>
44
+ <div id="el3">Element 3</div>
45
+ </div>
46
+ </body>
47
+ </html>
package/frame1.html ADDED
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Intersection Observer Frame Test</title>
5
+ </head>
6
+ <body>
7
+ <p>Hello World (1)</p>
8
+ </body>
9
+ </html>
package/frame2.html ADDED
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Intersection Observer Frame Test</title>
5
+ </head>
6
+ <body>
7
+ <p>Hello World (2)</p>
8
+ </body>
9
+ </html>
package/frames.html ADDED
@@ -0,0 +1,33 @@
1
+ <!--
2
+ Copyright 2016 Google Inc. All Rights Reserved.
3
+
4
+ Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
5
+
6
+ https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
7
+ -->
8
+ <!DOCTYPE html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="utf-8">
12
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
13
+ <title>IntersectionObserver Tests</title>
14
+
15
+ <!-- Dependencies -->
16
+ <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.5.3/mocha.min.css">
17
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.5.3/mocha.min.js"></script>
18
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/expect.js/0.2.0/expect.min.js"></script>
19
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/3.2.1/sinon.min.js"></script>
20
+
21
+ -->
22
+
23
+ <styles>
24
+
25
+ </styles>
26
+ </head>
27
+ <body>
28
+
29
+ <iframe src="frame1.html"></iframe>
30
+ <iframe src="frame2.html"></iframe>
31
+
32
+ </body>
33
+ </html>
@@ -1,17 +1,9 @@
1
1
  <!--
2
2
  Copyright 2016 Google Inc. All Rights Reserved.
3
3
 
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
4
+ Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
7
5
 
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
6
+ https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
15
7
  -->
16
8
  <!DOCTYPE html>
17
9
  <html lang="en">
@@ -24,7 +16,7 @@ limitations under the License.
24
16
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.5.3/mocha.min.css">
25
17
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.5.3/mocha.min.js"></script>
26
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/expect.js/0.2.0/expect.min.js"></script>
27
- <script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/1.15.4/sinon.min.js"></script>
19
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/3.2.1/sinon.min.js"></script>
28
20
 
29
21
  <!-- Polyfills for IE7-8 -->
30
22
  <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es5,getComputedStyle"></script>
@@ -1,17 +1,10 @@
1
1
  /**
2
2
  * Copyright 2016 Google Inc. All Rights Reserved.
3
3
  *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
4
+ * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
7
5
  *
8
- * http://www.apache.org/licenses/LICENSE-2.0
6
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
9
7
  *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
8
  */
16
9
 
17
10
 
@@ -142,14 +135,14 @@ describe('IntersectionObserver', function() {
142
135
  it('throws when a threshold is not a number', function() {
143
136
  expect(function() {
144
137
  io = new IntersectionObserver(noop, {threshold: ['foo']});
145
- }).to.throwException(/threshold/i);
138
+ }).to.throwException();
146
139
  });
147
140
 
148
141
 
149
142
  it('throws when a threshold value is not between 0 and 1', function() {
150
143
  expect(function() {
151
144
  io = new IntersectionObserver(noop, {threshold: [0, -1]});
152
- }).to.throwException(/threshold/i);
145
+ }).to.throwException();
153
146
  });
154
147
 
155
148
  });
@@ -161,7 +154,7 @@ describe('IntersectionObserver', function() {
161
154
  expect(function() {
162
155
  io = new IntersectionObserver(noop);
163
156
  io.observe(null);
164
- }).to.throwException(/element/i);
157
+ }).to.throwException();
165
158
  });
166
159
 
167
160
 
@@ -178,6 +171,20 @@ describe('IntersectionObserver', function() {
178
171
  io.observe(targetEl2);
179
172
  });
180
173
 
174
+ it('triggers for existing targets when observing begins after monitoring has begun', function(done) {
175
+ var spy = sinon.spy();
176
+ io = new IntersectionObserver(spy, {root: rootEl});
177
+
178
+ io.observe(targetEl1);
179
+ setTimeout(function() {
180
+ io.observe(targetEl2);
181
+ setTimeout(function() {
182
+ expect(spy.callCount).to.be(2);
183
+ done();
184
+ }, ASYNC_TIMEOUT);
185
+ }, ASYNC_TIMEOUT);
186
+ });
187
+
181
188
 
182
189
  it('triggers with the correct arguments', function(done) {
183
190
  io = new IntersectionObserver(function(records, observer) {
@@ -632,7 +639,7 @@ describe('IntersectionObserver', function() {
632
639
 
633
640
  // targetEl5 is initially not in the DOM. Note that this element must be
634
641
  // created outside of the addFixtures() function to catch the IE11 error
635
- // described here: https://github.com/WICG/IntersectionObserver/pull/205
642
+ // described here: https://github.com/w3c/IntersectionObserver/pull/205
636
643
  var targetEl5 = document.createElement('div');
637
644
  targetEl5.setAttribute('id', 'target5');
638
645
 
@@ -1,17 +1,10 @@
1
1
  /**
2
2
  * Copyright 2016 Google Inc. All Rights Reserved.
3
3
  *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
4
+ * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
7
5
  *
8
- * http://www.apache.org/licenses/LICENSE-2.0
6
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
9
7
  *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
8
  */
16
9
 
17
10
  (function(window, document) {
@@ -25,7 +18,7 @@ if ('IntersectionObserver' in window &&
25
18
  'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
26
19
 
27
20
  // Minimal polyfill for Edge 15's lack of `isIntersecting`
28
- // See: https://github.com/WICG/IntersectionObserver/issues/211
21
+ // See: https://github.com/w3c/IntersectionObserver/issues/211
29
22
  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
30
23
  Object.defineProperty(window.IntersectionObserverEntry.prototype,
31
24
  'isIntersecting', {
@@ -40,7 +33,7 @@ if ('IntersectionObserver' in window &&
40
33
 
41
34
  /**
42
35
  * An IntersectionObserver registry. This registry exists to hold a strong
43
- * reference to IntersectionObserver instances currently observering a target
36
+ * reference to IntersectionObserver instances currently observing a target
44
37
  * element. Without this registry, instances without another reference may be
45
38
  * garbage collected.
46
39
  */
@@ -49,7 +42,7 @@ var registry = [];
49
42
 
50
43
  /**
51
44
  * Creates the global IntersectionObserverEntry constructor.
52
- * https://wicg.github.io/IntersectionObserver/#intersection-observer-entry
45
+ * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
53
46
  * @param {Object} entry A dictionary of instance properties.
54
47
  * @constructor
55
48
  */
@@ -69,7 +62,9 @@ function IntersectionObserverEntry(entry) {
69
62
 
70
63
  // Sets intersection ratio.
71
64
  if (targetArea) {
72
- this.intersectionRatio = intersectionArea / targetArea;
65
+ // Round the intersection ratio to avoid floating point math issues:
66
+ // https://github.com/w3c/IntersectionObserver/issues/324
67
+ this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
73
68
  } else {
74
69
  // If area is zero and is intersecting, sets to 1, otherwise to 0
75
70
  this.intersectionRatio = this.isIntersecting ? 1 : 0;
@@ -79,7 +74,7 @@ function IntersectionObserverEntry(entry) {
79
74
 
80
75
  /**
81
76
  * Creates the global IntersectionObserver constructor.
82
- * https://wicg.github.io/IntersectionObserver/#intersection-observer-interface
77
+ * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
83
78
  * @param {Function} callback The function to be invoked after intersection
84
79
  * changes have queued. The function is not invoked if the queue has
85
80
  * been emptied by calling the `takeRecords` method.
@@ -131,6 +126,12 @@ IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;
131
126
  */
132
127
  IntersectionObserver.prototype.POLL_INTERVAL = null;
133
128
 
129
+ /**
130
+ * Use a mutation observer on the root element
131
+ * to detect intersection changes.
132
+ */
133
+ IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;
134
+
134
135
 
135
136
  /**
136
137
  * Starts observing a target element for intersection changes based on
@@ -138,10 +139,11 @@ IntersectionObserver.prototype.POLL_INTERVAL = null;
138
139
  * @param {Element} target The DOM element to observe.
139
140
  */
140
141
  IntersectionObserver.prototype.observe = function(target) {
141
- // If the target is already being observed, do nothing.
142
- if (this._observationTargets.some(function(item) {
142
+ var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
143
143
  return item.element == target;
144
- })) {
144
+ });
145
+
146
+ if (isTargetAlreadyObserved) {
145
147
  return;
146
148
  }
147
149
 
@@ -152,6 +154,7 @@ IntersectionObserver.prototype.observe = function(target) {
152
154
  this._registerInstance();
153
155
  this._observationTargets.push({element: target, entry: null});
154
156
  this._monitorIntersections();
157
+ this._checkForIntersections();
155
158
  };
156
159
 
157
160
 
@@ -249,15 +252,13 @@ IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
249
252
 
250
253
  /**
251
254
  * Starts polling for intersection changes if the polling is not already
252
- * happening, and if the page's visibilty state is visible.
255
+ * happening, and if the page's visibility state is visible.
253
256
  * @private
254
257
  */
255
258
  IntersectionObserver.prototype._monitorIntersections = function() {
256
259
  if (!this._monitoringIntersections) {
257
260
  this._monitoringIntersections = true;
258
261
 
259
- this._checkForIntersections();
260
-
261
262
  // If a poll interval is set, use polling instead of listening to
262
263
  // resize and scroll events or DOM mutations.
263
264
  if (this.POLL_INTERVAL) {
@@ -268,7 +269,7 @@ IntersectionObserver.prototype._monitorIntersections = function() {
268
269
  addEvent(window, 'resize', this._checkForIntersections, true);
269
270
  addEvent(document, 'scroll', this._checkForIntersections, true);
270
271
 
271
- if ('MutationObserver' in window) {
272
+ if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
272
273
  this._domObserver = new MutationObserver(this._checkForIntersections);
273
274
  this._domObserver.observe(document, {
274
275
  attributes: true,
@@ -358,7 +359,7 @@ IntersectionObserver.prototype._checkForIntersections = function() {
358
359
  * Accepts a target and root rect computes the intersection between then
359
360
  * following the algorithm in the spec.
360
361
  * TODO(philipwalton): at this time clip-path is not considered.
361
- * https://wicg.github.io/IntersectionObserver/#calculate-intersection-rect-algo
362
+ * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo
362
363
  * @param {Element} target The target DOM element
363
364
  * @param {Object} rootRect The bounding rect of the root after being
364
365
  * expanded by the rootMargin value.
@@ -553,7 +554,7 @@ function now() {
553
554
 
554
555
 
555
556
  /**
556
- * Throttles a function and delays its executiong, so it's only called at most
557
+ * Throttles a function and delays its execution, so it's only called at most
557
558
  * once within a given time period.
558
559
  * @param {Function} fn The function to throttle.
559
560
  * @param {number} timeout The amount of time that must pass before the
@@ -647,7 +648,7 @@ function getBoundingClientRect(el) {
647
648
  rect = el.getBoundingClientRect();
648
649
  } catch (err) {
649
650
  // Ignore Windows 7 IE11 "Unspecified error"
650
- // https://github.com/WICG/IntersectionObserver/pull/205
651
+ // https://github.com/w3c/IntersectionObserver/pull/205
651
652
  }
652
653
 
653
654
  if (!rect) return getEmptyRect();
@@ -684,7 +685,7 @@ function getEmptyRect() {
684
685
  }
685
686
 
686
687
  /**
687
- * Checks to see if a parent element contains a child elemnt (including inside
688
+ * Checks to see if a parent element contains a child element (including inside
688
689
  * shadow DOM).
689
690
  * @param {Node} parent The parent element.
690
691
  * @param {Node} child The child element.
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "intersection-observer",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "A polyfill for IntersectionObserver",
5
5
  "main": "intersection-observer",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git@github.com:WICG/IntersectionObserver.git"
8
+ "url": "git@github.com:w3c/IntersectionObserver.git"
9
9
  },
10
10
  "keywords": [
11
11
  "Intersection",
@@ -16,8 +16,8 @@
16
16
  "email": "philip@philipwalton.com",
17
17
  "url": "http://philipwalton.com"
18
18
  },
19
- "license": "Apache-2.0",
19
+ "license": "W3C-20150513",
20
20
  "bugs": {
21
- "url": "https://github.com/WICG/IntersectionObserver/issues"
21
+ "url": "https://github.com/w3c/IntersectionObserver/issues"
22
22
  }
23
23
  }
package/slot.html ADDED
@@ -0,0 +1,93 @@
1
+ <template id="slot-test">
2
+ <style>
3
+
4
+ </style>
5
+ <div>
6
+ <h3>Title</h3>
7
+ <aside>
8
+ <slot name="contents"></slot>
9
+ </aside>
10
+ </div>
11
+ </template>
12
+
13
+
14
+ <my-el>
15
+ <ul slot="contents">
16
+ <li>one</li>
17
+ <li>two</li>
18
+ <li>three</li>
19
+ </ul>
20
+ <ul slot="contents">
21
+ <li>four</li>
22
+ <li>five</li>
23
+ <li>six</li>
24
+ </ul>
25
+ </my-el>
26
+
27
+
28
+ <script>
29
+ class MyEl extends HTMLElement {
30
+ constructor() {
31
+ super();
32
+
33
+ const shadowRoot = this.attachShadow({mode: 'open'});
34
+ shadowRoot.innerHTML = `
35
+ <style>
36
+
37
+ </style>
38
+ <div>
39
+ <h3>Title</h3>
40
+ <aside>
41
+ <slot name="contents"></slot>
42
+ </aside>
43
+ </div>
44
+ `;
45
+ }
46
+ }
47
+
48
+ self.customElements.define('my-el', MyEl);
49
+
50
+
51
+ /**
52
+ * Checks to see if a parent element contains a child elemnt (including inside
53
+ * shadow DOM).
54
+ * @param {Node} parent The parent element.
55
+ * @param {Node} child The child element.
56
+ * @return {boolean} True if the parent node contains the child node.
57
+ */
58
+ function containsDeep(parent, child) {
59
+ var node = child;
60
+ while (node) {
61
+ if (node == parent) return true;
62
+
63
+ node = getParentNode(node);
64
+ }
65
+ return false;
66
+ }
67
+
68
+
69
+ /**
70
+ * Gets the parent node of an element or its host element if the parent node
71
+ * is a shadow root.
72
+ * @param {Node} node The node whose parent to get.
73
+ * @return {Node|null} The parent node or null if no parent exists.
74
+ */
75
+ function getParentNode(node) {
76
+ var parent = node.parentNode;
77
+
78
+ if (parent) {
79
+ if (parent.nodeType == 11 && parent.host) {
80
+ // If the parent is a shadow root, return the host element.
81
+ return parent.host;
82
+ }
83
+
84
+ if (parent.assignedSlot) {
85
+ // If the parent is assigned a slot, return the slot's parent.
86
+ return parent.assignedSlot.parentNode;
87
+ }
88
+ }
89
+ return parent;
90
+ }
91
+
92
+
93
+ </script>
package/.npmignore DELETED
@@ -1,3 +0,0 @@
1
- # Sauce Labs testing files
2
- easy-sauce-config.json
3
- sauce.sh