intersection-observer 0.4.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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