Skip to content

Commit fa7bca7

Browse files
committed
Initial commit
0 parents  commit fa7bca7

File tree

5 files changed

+397
-0
lines changed

5 files changed

+397
-0
lines changed

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# scroll-into-view-if-needed
2+
3+
This is a [ponyfill](https://ponyfoo.com/articles/polyfills-or-ponyfills) with the added ability of animating the scroll itself.
4+
5+
Kudos to [@hsablonniere](https://github.com/hsablonniere) for sharing the [original polyfill](https://gist.github.com/hsablonniere/2581101)
6+
7+
## Install
8+
9+
```bash
10+
npm install scroll-into-view-if-needed
11+
```
12+
13+
## API
14+
15+
### scrollIntoViewIfNeeded(node:Element, centerIfNeeded:boolean || options:object)
16+
17+
Returns a function that can be used to cancel a scroll animation.
18+
19+
#### Options
20+
21+
##### centerIfNeeded
22+
23+
This defaults to true to match the behavior of the WebKit/Blink implementation.
24+
Set it to false to actually only scroll the parent when needed and not further than absolutely necessary.
25+
26+
##### duration
27+
28+
The duration of the animation in milliseconds, defaults to 0 for no animation.
29+
30+
##### easing
31+
32+
@TODO
33+
34+
## Examples
35+
36+
```javascript
37+
import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed'
38+
39+
const activeNode = document.querySelector('li.active')
40+
41+
// Works just like Element.scrollIntoViewIfNeeded in WebKit and Blink
42+
scrollIntoViewIfNeeded(activeNode, false)
43+
44+
// Animates it with a tiny animation lib, no need for jQuery or Velocity
45+
scrollIntoViewIfNeeded(activeNode, {
46+
centerIfNeeded: false,
47+
duration: 150
48+
})
49+
50+
```

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "scroll-into-view-if-needed",
3+
"version": "1.0.0",
4+
"description": "Element.scrollIntoViewIfNeeded ponyfill that can animate the scrolling",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/stipsan/scroll-into-view-if-needed.git"
12+
},
13+
"keywords": [
14+
"ponyfill",
15+
"smooth",
16+
"scroll",
17+
"scroll-into-view",
18+
"scroll"
19+
],
20+
"author": "Stian Didriksen",
21+
"license": "MIT",
22+
"bugs": {
23+
"url": "https://github.com/stipsan/scroll-into-view-if-needed/issues"
24+
},
25+
"homepage": "https://github.com/stipsan/scroll-into-view-if-needed#readme"
26+
}

src/index.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
if (!Element.prototype.scrollIntoViewIfNeeded) {
2+
Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
3+
centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded;
4+
5+
var parent = this.parentNode,
6+
parentComputedStyle = window.getComputedStyle(parent, null),
7+
parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
8+
parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
9+
overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
10+
overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
11+
overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
12+
overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
13+
alignWithTop = overTop && !overBottom;
14+
15+
if ((overTop || overBottom) && centerIfNeeded) {
16+
parent.scrollTop = this.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + this.clientHeight / 2;
17+
}
18+
19+
if ((overLeft || overRight) && centerIfNeeded) {
20+
parent.scrollLeft = this.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + this.clientWidth / 2;
21+
}
22+
23+
if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
24+
this.scrollIntoView(alignWithTop);
25+
}
26+
};
27+
}

test/test-horizontal.html

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<!DOCTYPE html>
2+
<title>scrollIntoViewIfNeeded test page</title>
3+
4+
<style type="text/css">
5+
body {
6+
font: 14px Arial;
7+
}
8+
#scroll-area {
9+
border: 1px solid #AAA;
10+
height: 7em;
11+
margin: 0;
12+
overflow: auto;
13+
padding: 0;
14+
width: 400px;
15+
white-space: nowrap;
16+
}
17+
#scroll-area li {
18+
background: #EEE;
19+
border-radius: 5px;
20+
display: inline-block;
21+
list-style: none;
22+
padding: 5px 10px;
23+
}
24+
#scroll-area li:nth-child(2n+1) {
25+
background: #DDD;
26+
text-align: right;
27+
}
28+
#scroll-area li.selected {
29+
background: #BADA55;
30+
}
31+
</style>
32+
33+
<h1>scrollIntoViewIfNeeded test page</h1>
34+
35+
<ul id="scroll-area"><li class="selected">item #0</li><li>item #1</li><li>item #2</li><li>item #3</li><li>item #4</li><li>item #5</li><li>item #6</li><li>item #7</li><li>item #8</li><li>item #9</li><li>item #10</li><li>item #11</li><li>item #12</li><li>item #13</li><li>item #14</li><li>item #15</li><li>item #16</li><li>item #17</li><li>item #18</li><li>item #19</li><li>item #20</li><li>item #21</li><li>item #22</li><li>item #23</li><li>item #24</li><li>item #25</li><li>item #26</li><li>item #27</li><li>item #28</li><li>item #29</li><li>item #30</li><li>item #31</li><li>item #32</li><li>item #33</li><li>item #34</li><li>item #35</li><li>item #36</li><li>item #37</li><li>item #38</li><li>item #39</li><li>item #40</li><li>item #41</li><li>item #42</li><li>item #43</li><li>item #44</li><li>item #45</li><li>item #46</li><li>item #47</li><li>item #48</li><li>item #49</li><li>item #50</li><li>item #51</li><li>item #52</li><li>item #53</li><li>item #54</li><li>item #55</li><li>item #56</li><li>item #57</li><li>item #58</li><li>item #59</li><li>item #60</li><li>item #61</li><li>item #62</li><li>item #63</li><li>item #64</li><li>item #65</li><li>item #66</li><li>item #67</li><li>item #68</li><li>item #69</li><li>item #70</li><li>item #71</li><li>item #72</li><li>item #73</li><li>item #74</li><li>item #75</li><li>item #76</li><li>item #77</li><li>item #78</li><li>item #79</li><li>item #80</li><li>item #81</li><li>item #82</li><li>item #83</li><li>item #84</li><li>item #85</li><li>item #86</li><li>item #87</li><li>item #88</li><li>item #89</li><li>item #90</li><li>item #91</li><li>item #92</li><li>item #93</li><li>item #94</li><li>item #95</li><li>item #96</li><li>item #97</li><li>item #98</li><li>item #99</li></ul>
36+
37+
<div id="buttons-centerFalse">
38+
<span><code>scrollIntoViewIfNeeded(false)</code> to item : </span>
39+
<button data-item-idx="0">#0</button>
40+
<button data-item-idx="11">#11</button>
41+
<button data-item-idx="22">#22</button>
42+
<button data-item-idx="24">#24</button>
43+
<button data-item-idx="26">#26</button>
44+
<button data-item-idx="33">#33</button>
45+
<button data-item-idx="44">#44</button>
46+
<button data-item-idx="55">#55</button>
47+
<button data-item-idx="66">#66</button>
48+
<button data-item-idx="77">#77</button>
49+
<button data-item-idx="82">#82</button>
50+
<button data-item-idx="84">#84</button>
51+
<button data-item-idx="86">#86</button>
52+
<button data-item-idx="99">#99</button>
53+
</div>
54+
55+
<div id="buttons-centerTrue">
56+
<span><code>scrollIntoViewIfNeeded(true)</code> to item : </span>
57+
<button data-item-idx="0">#0</button>
58+
<button data-item-idx="11">#11</button>
59+
<button data-item-idx="22">#22</button>
60+
<button data-item-idx="24">#24</button>
61+
<button data-item-idx="26">#26</button>
62+
<button data-item-idx="33">#33</button>
63+
<button data-item-idx="44">#44</button>
64+
<button data-item-idx="55">#55</button>
65+
<button data-item-idx="66">#66</button>
66+
<button data-item-idx="77">#77</button>
67+
<button data-item-idx="82">#82</button>
68+
<button data-item-idx="84">#84</button>
69+
<button data-item-idx="86">#86</button>
70+
<button data-item-idx="99">#99</button>
71+
</div>
72+
73+
<div id="buttons-centerUndefined">
74+
<span><code>scrollIntoViewIfNeeded(undefined)</code> to item : </span>
75+
<button data-item-idx="0">#0</button>
76+
<button data-item-idx="11">#11</button>
77+
<button data-item-idx="22">#22</button>
78+
<button data-item-idx="24">#24</button>
79+
<button data-item-idx="26">#26</button>
80+
<button data-item-idx="33">#33</button>
81+
<button data-item-idx="44">#44</button>
82+
<button data-item-idx="55">#55</button>
83+
<button data-item-idx="66">#66</button>
84+
<button data-item-idx="77">#77</button>
85+
<button data-item-idx="82">#82</button>
86+
<button data-item-idx="84">#84</button>
87+
<button data-item-idx="86">#86</button>
88+
<button data-item-idx="99">#99</button>
89+
</div>
90+
91+
<div id="buttons-centerNoArgs">
92+
<span><code>scrollIntoViewIfNeeded()</code> to item : </span>
93+
<button data-item-idx="0">#0</button>
94+
<button data-item-idx="11">#11</button>
95+
<button data-item-idx="22">#22</button>
96+
<button data-item-idx="24">#24</button>
97+
<button data-item-idx="26">#26</button>
98+
<button data-item-idx="33">#33</button>
99+
<button data-item-idx="44">#44</button>
100+
<button data-item-idx="55">#55</button>
101+
<button data-item-idx="66">#66</button>
102+
<button data-item-idx="77">#77</button>
103+
<button data-item-idx="82">#82</button>
104+
<button data-item-idx="84">#84</button>
105+
<button data-item-idx="86">#86</button>
106+
<button data-item-idx="99">#99</button>
107+
</div>
108+
109+
<script src="../src/index.js"></script>
110+
<script>
111+
(function () {
112+
var scrollArea = document.getElementById('scroll-area'),
113+
buttonsCenterFalse = document.getElementById('buttons-centerFalse'),
114+
buttonsCenterTrue = document.getElementById('buttons-centerTrue'),
115+
buttonsCenterUndefined = document.getElementById('buttons-centerUndefined'),
116+
buttonsCenterNoArgs = document.getElementById('buttons-centerNoArgs'),
117+
scrollIntoViewIfNeededToItemAndSelect;
118+
scrollIntoViewIfNeededToItemAndSelect = function (itemIdx, centerIfNeeded) {
119+
scrollArea.querySelector('.selected').className = '';
120+
// Allow us to really have difference bewteen scrollIntoViewIfNeeded() and scrollIntoViewIfNeeded(undefined)
121+
if (arguments.length === 1) {
122+
scrollArea.children[itemIdx].scrollIntoViewIfNeeded();
123+
} else {
124+
scrollArea.children[itemIdx].scrollIntoViewIfNeeded(centerIfNeeded);
125+
}
126+
scrollArea.children[itemIdx].className = 'selected';
127+
};
128+
buttonsCenterFalse.addEventListener('click', function (e) {
129+
if (e.target.nodeName === 'BUTTON') {
130+
scrollIntoViewIfNeededToItemAndSelect(e.target.dataset.itemIdx, false);
131+
}
132+
}, false);
133+
buttonsCenterTrue.addEventListener('click', function (e) {
134+
if (e.target.nodeName === 'BUTTON') {
135+
scrollIntoViewIfNeededToItemAndSelect(e.target.dataset.itemIdx, true);
136+
}
137+
}, false);
138+
buttonsCenterUndefined.addEventListener('click', function (e) {
139+
if (e.target.nodeName === 'BUTTON') {
140+
scrollIntoViewIfNeededToItemAndSelect(e.target.dataset.itemIdx, undefined);
141+
}
142+
}, false);
143+
buttonsCenterNoArgs.addEventListener('click', function (e) {
144+
if (e.target.nodeName === 'BUTTON') {
145+
scrollIntoViewIfNeededToItemAndSelect(e.target.dataset.itemIdx);
146+
}
147+
}, false);
148+
})();
149+
</script>

0 commit comments

Comments
 (0)