forked from patik/within-viewport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
withinViewport.js
167 lines (152 loc) · 5.47 KB
/
withinViewport.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* Within Viewport
*
* @description Determines whether an element is completely
* within the browser viewport
* @author Craig Patik, http://patik.com/
* @version 0.2
* @date 2011-11-05
*/
;(function(d) {
/**
* withinViewport
* @param {Object} [elem] DOM Element, required
* @param {Object} [settings] optional settings
* @return {Boolean} whether elem was completely within the viewport
*/
var withinViewport = function(elem, settings)
{
var result = false;
try {
if (typeof elem !== "object" || elem.nodeType !== 1) {
throw new Error("First argument should be a DOM element");
}
var arr, i, side, // Temporary variables for looping
metadata = elem.getAttribute("data-withinviewport-settings") && window.JSON
? JSON.parse(elem.getAttribute("data-withinviewport-settings"))
: {},
// settings argument may be a simple: string 'top', 'right', etc
settings = typeof settings === "string" ? {sides: settings} : settings || {},
// Build configuration from defaults and given settings
config = {
sides: settings.sides || metadata.sides || withinViewport.defaults.sides || "all",
top: settings.top || metadata.top || withinViewport.defaults.top || 0,
right: settings.right || metadata.right || withinViewport.defaults.right || 0,
bottom: settings.bottom || metadata.bottom || withinViewport.defaults.bottom || 0,
left: settings.left || metadata.left || withinViewport.defaults.left || 0
},
// Element testing methods
isWithin = {
// Element is below the top edge of the viewport
top: function() {
return elemOffset[1]
>= scrollOffset[1] + config.top;
},
// Element is to the left of the right edge of the viewport
right: function() {
var width = window.innerWidth || document.documentElement.clientWidth;
return elemOffset[0] + elem.offsetWidth
<= width + scrollOffset[0] - config.right;
},
// Element is above the bottom edge of the viewport
bottom: function() {
var height = window.innerHeight || document.documentElement.clientHeight;
return elemOffset[1] + elem.offsetHeight
<= height + scrollOffset[1] - config.bottom;
},
// Element is to the right of the left edge of the viewport
left: function() {
return elemOffset[0]
>= scrollOffset[0] + config.left;
},
all: function() {
return (isWithin.top() && isWithin.right() && isWithin.bottom() && isWithin.left());
}
},
// Current offset values
scrollOffset = (function() {
var x = d.body.scrollLeft,
y = d.body.scrollTop;
if (y == 0) {
if (window.pageYOffset) {
y = window.pageYOffset;
}
else {
y = (d.body.parentElement) ? d.body.parentElement.scrollTop : 0;
}
}
if (x == 0) {
if (window.pageXOffset) {
x = window.pageXOffset;
}
else {
x = (d.body.parentElement) ? d.body.parentElement.scrollLeft : 0;
}
}
return [x, y];
})(),
elemOffset = (function() {
var el = elem,
x = 0,
y = 0;
if (el.offsetParent) {
x = el.offsetLeft;
y = el.offsetTop;
while (el = el.offsetParent) {
x += el.offsetLeft;
y += el.offsetTop;
}
}
return [x, y];
})();
// Test element against each side of the viewport that was requested
arr = config.sides.split(" ");
i = arr.length;
while (i--) {
side = arr[i].toLowerCase();
if (/top|right|bottom|left|all/.test(side)) {
if (isWithin[side]()) {
result = true;
}
else {
// Quit as soon as we find the first failure
return false;
}
}
}
return result;
}
catch(e) { }
finally {
return result;
}
};
// Default settings
withinViewport.prototype.defaults = {
sides: "all",
top: 0,
right: 0,
bottom: 0,
left: 0
};
withinViewport.defaults = withinViewport.prototype.defaults;
// Make function available globally
window.withinViewport = withinViewport;
/**
* Optional enhancements and shortcuts
*
* @description Uncomment or comment these pieces as they apply to your project and coding preferences
*/
// Shortcut methods for each side of the viewport
// Ex: withinViewport.top(elem) is the same as withinViewport(elem, "top")
//
var arr = ['top', 'right', 'bottom', 'left'];
var i = arr.length;
while(i--) {
var side = arr[i];
withinViewport.prototype[side] = function(element) {
return withinViewport(element, side);
};
withinViewport[side] = withinViewport.prototype[side];
}
})(document);