Skip to content

Commit c054aab

Browse files
authored
Merge pull request #53 from stutrek/dom-element-containers
Allow DOM element containers
2 parents 37d1061 + 4af36c0 commit c054aab

24 files changed

+1539
-955
lines changed

.eslintrc.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"parser": "babel-eslint",
3+
"extends": "eslint:recommended",
4+
"env": {
5+
"browser": true,
6+
"node": true,
7+
"amd": true,
8+
"commonjs": true,
9+
"es6": true
10+
},
11+
"globals": {
12+
"app": true,
13+
"PROD": false,
14+
"DEV": false
15+
},
16+
"parserOptions": {
17+
"ecmaFeatures": {
18+
"modules": true,
19+
"jsx": true
20+
},
21+
"ecmaVersion": 6,
22+
"sourceType": "module",
23+
"jsx": true
24+
},
25+
"plugins": [
26+
"react"
27+
],
28+
"rules": {
29+
"eqeqeq": 2,
30+
"quotes": [1, "single"],
31+
"no-console": 1,
32+
"dot-location": [1, "property"],
33+
"no-caller": 2,
34+
"no-fallthrough": 2,
35+
"no-floating-decimal": 1,
36+
"no-loop-func": 0,
37+
"no-new-func": 2,
38+
"no-sequences": 1,
39+
"no-throw-literal": 2,
40+
"no-label-var": 2,
41+
"no-shadow-restricted-names": 2,
42+
"no-shadow": 2,
43+
"no-use-before-define": 2,
44+
"react/jsx-uses-vars": 2,
45+
"camelcase": 1,
46+
"no-lonely-if": 1,
47+
"no-nested-ternary": 2,
48+
"no-unneeded-ternary": 1,
49+
"no-trailing-spaces": 1,
50+
"semi": 2
51+
}
52+
}

README.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
scrollMonitor
22
=============
33

4-
The scroll monitor allows you to receive events when elements enter or exit the viewport. It does this using watcher objects, which watch an element and trigger events. Watcher objects also contain information about the element they watch, including the element's visibility and location relative to the viewport.
4+
The scroll monitor allows you to receive events when elements enter or exit a viewport. It does this using watcher objects, which watch an element and trigger events. Watcher objects also contain information about the element they watch, including the element's visibility and location relative to the viewport. If your scroll container is an element other than the body you can create a container that creates watchers.
55

66
The scroll monitor was designed to be very fast. On each scroll event the DOM is only touched twice, once to find the document height and again to find the viewport top. No variables are declared, nor are any objects, arrays, or strings created.
77

8-
The code is based on vanilla javascript and has no external dependencies. Except if you want to put it in the head of the document, then you'll need jQuery for the DOMContentLoaded event.
8+
The code is based on vanilla javascript and has no external dependencies. _The script cannot be put in the head_.
99

1010
Watchers are _very_ cheap. Create them liberally.
1111

12-
[![browser support](http://ci.testling.com/sakabako/scrollMonitor.png)](http://ci.testling.com/sakabako/scrollMonitor)
13-
1412
## Basic Usage
1513

14+
### When the body scrolls
15+
1616
```javascript
1717
var scrollMonitor = require("./scrollMonitor"); // if you're not using require, you can use the scrollMonitor global.
1818
var myElement = document.getElementById("itemToWatch");
@@ -26,9 +26,34 @@ elementWatcher.exitViewport(function() {
2626
console.log( 'I have left the viewport' );
2727
});
2828
```
29+
30+
### For a scroll container
31+
32+
```javascript
33+
var containerElement = document.getElementById("container");
34+
35+
var containerMonitor = scrollMonitor.createContainer(containerElement);
36+
// this containerMonitor is an instance of the scroll monitor
37+
// that listens to scroll events on your container.
38+
39+
var childElement = document.getElementById("child-of-container");
40+
var elementWatcher = containerMonitor.create(childElement);
41+
42+
elementWatcher.enterViewport(function() {
43+
console.log( 'I have entered the viewport' );
44+
});
45+
elementWatcher.exitViewport(function() {
46+
console.log( 'I have left the viewport' );
47+
});
48+
```
49+
50+
_Note: an element is said to be in the viewport if it is scrolled into its parent, it does not matter if the parent is in the viewport._
51+
2952
## Demos
3053

3154
* [Stress Test](http://stutrek.github.com/scrollMonitor/demos/stress.html) - Test with as many watchers as you'd like
55+
* [Stress Test in a div](http://stutrek.github.com/scrollMonitor/demos/stressTestInADiv.html) - Note how much slower scrolling a div is than scrolling the body.
56+
* [Nested scrollers](http://stutrek.github.com/scrollMonitor/demos/divInADiv.html)
3257
* [Fixed Positioning and Locking](http://stutrek.github.com/scrollMonitor/demos/fixed.html)
3358
* [Anchored section headers](http://stutrek.github.com/scrollMonitor/demos/list.html)
3459
* [Complex sidebar behavior](http://stutrek.github.com/scrollMonitor/demos/scoreboard.html)
@@ -134,6 +159,7 @@ scrollMonitor.create( element, -200 )
134159
## scrollMonitor Module
135160

136161
### Methods
162+
* `scrollMonitor.createContainer( containerEl )` - returns a new ScrollMonitorContainer that can be used just like the scrollMonitor module.
137163
* `scrollMonitor.create( watchItem, offsets )` - Returns a new watcher. `watchItem` is a DOM element, jQuery object, NodeList, CSS selector, object with .top and .bottom, or a number.
138164
* `scrollMonitor.update()` - update and trigger all watchers.
139165
* `scrollMonitor.recalculateLocations()` - recalculate the location of all unlocked watchers and trigger if needed.
@@ -144,3 +170,13 @@ scrollMonitor.create( element, -200 )
144170
* `scrollMonitor.viewportHeight` - height of the viewport.
145171
* `scrollMonitor.documentHeight` - height of the document.
146172

173+
# Contributing
174+
175+
There is a set of unit tests written with Mocha + Chai that run in testem. Getting them running is simple:
176+
177+
```
178+
npm install
179+
npm test
180+
```
181+
182+
then open http://localhost:7357

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "scrollMonitor",
3-
"version": "1.1.3",
3+
"version": "1.2.0",
44
"main": "./scrollMonitor.js",
55
"dependencies": {},
66
"devDependencies": {},

demos/divInADiv.html

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<!doctype html>
2+
<head>
3+
<style type="text/css">
4+
* {
5+
box-sizing: border-box;
6+
}
7+
body {
8+
margin: 0;
9+
padding: 0;
10+
font-family: Helvetica, Arial, sans-serif;
11+
}
12+
.screen {
13+
height: 100vh;
14+
width: 100%;
15+
position: relative;
16+
min-height: 900px;
17+
}
18+
.content {
19+
position: absolute;
20+
height: 400px;
21+
width: 615px;
22+
padding: 15px;
23+
top: 50%;
24+
left: 50%;
25+
transform: translate(-50%, -50%);
26+
margin: auto;
27+
background-color: white;
28+
}
29+
.content img {
30+
width: 100%;
31+
}
32+
.one {
33+
background-color: silver;
34+
}
35+
.two {
36+
background-color: #c00;
37+
}
38+
.three {
39+
background-color: #00c;
40+
}
41+
h1 {
42+
margin-top: 0;
43+
}
44+
.insert-boxes-here {
45+
margin: 0 -5px;
46+
}
47+
.box {
48+
display: inline-block;
49+
background-color: #ccc;
50+
width: 75px;
51+
height: 75px;
52+
margin: 5px;
53+
line-height: 75px;
54+
text-align: center;
55+
color: #999;
56+
/*border: 1px solid black;*/
57+
}
58+
.box.in {
59+
background-color: #fcc;
60+
}
61+
.box.partial-above {
62+
background-color: #ccf;
63+
}
64+
.box.partial-below {
65+
background-color: #ffc;
66+
}
67+
68+
.internal {
69+
height: 300px;
70+
margin: 0 73px 10px;
71+
text-align: center;
72+
background-color: #aaa;
73+
}
74+
75+
.scroller {
76+
overflow-y: auto;
77+
}
78+
</style>
79+
</head>
80+
<body>
81+
<div>
82+
<div class="screen one">
83+
<div class="content scroller">
84+
<h1>Here are a couple of boxes from the stress test.</h1>
85+
<div class="insert-boxes-here"></div>
86+
</div>
87+
</div>
88+
<div class="screen two">
89+
<div class="content scroller">
90+
<h1>And a few more, just to prove that it works down here too.</h1>
91+
<div class="insert-boxes-here"></div>
92+
</div>
93+
</div>
94+
<div class="screen three">
95+
<div class="content scroller">
96+
<h1>And a scroller in a scroller.</h1>
97+
<div class="internal scroller">
98+
<h2>Just for you.</h2>
99+
<div class="insert-boxes-here"></div>
100+
</div>
101+
<div class="insert-boxes-here"></div>
102+
</div>
103+
</div>
104+
</div>
105+
<a href="https://github.com/sakabako/scrollMonitor"><img style="position: fixed; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub"></a>
106+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
107+
<script src="../scrollMonitor.js"></script>
108+
<script type="text/javascript">
109+
var boxHtml = (new Array(100)).join('<span class="box"></span>');
110+
$('.insert-boxes-here').html(boxHtml);
111+
112+
function listener(event, watcher) {
113+
if (!watcher.isInViewport) {
114+
return;
115+
} else if (watcher.isFullyInViewport) {
116+
watcher.watchItem.style.backgroundColor = '#fcc';
117+
} else if (watcher.isAboveViewport) {
118+
watcher.watchItem.style.backgroundColor = '#ccf';
119+
} else if (watcher.isBelowViewport) {
120+
watcher.watchItem.style.backgroundColor = '#ffc';
121+
}
122+
}
123+
124+
$('.scroller').each(function (i, element) {
125+
var boxes = $('> .insert-boxes-here > .box', element);
126+
var container = scrollMonitor.createContainer(element);
127+
boxes.each(function (i, boxEl) {
128+
var watcher = container.create(boxEl);
129+
watcher.stateChange(listener);
130+
listener(null, watcher);
131+
});
132+
});
133+
134+
</script>
135+
</body>

demos/fixed.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<script src="../scrollMonitor.js"></script>
4141
<script type="text/javascript">
4242

43-
$('span').each(function(i, element) {
43+
var watchers = $('span').map(function(i, element) {
4444

4545
var watcher = scrollMonitor.create( element );
4646

@@ -49,8 +49,9 @@
4949
watcher.stateChange(function() {
5050
$(element).toggleClass('fixed', this.isAboveViewport)
5151
});
52-
53-
})
52+
return watcher;
53+
});
54+
console.log(watchers);
5455

5556
</script>
56-
</body>
57+
</body>

0 commit comments

Comments
 (0)