-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
115 lines (107 loc) · 3.68 KB
/
index.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
// Generates add and remove listeners for resize events
function resizeFrame() {
let animationFrame = window.requestAnimationFrame(loop)
let callbackCollection = []
let lastDocHeight = -1 // document.documentElement.scrollHeight
let lastDocWidth = -1 // document.documentElement.scrollWidth
let lastClientHeight = -1 // document.documentElement.clientHeight
let lastClientWidth = -1 // document.documentElement.clientWidth
/**
* Object that holds a callback function and data about how to handle it
*
* @param {function} func The callback function
* @param {boolean} breakOnError If callback function throws an error, remove from resize listener
*/
function Callback(func, breakOnError) {
this.func = func
this.breakOnError = breakOnError
}
/**
* Determines if any resize has occurred and callbacks exist to initiate a trigger
*/
function loop () {
// Only process checks if callback exists
if (callbackCollection.length) {
// Only process loop if we are resizing
const docHeight = document.documentElement.scrollHeight
const docWidth = document.documentElement.scrollWidth
const clientHeight = document.documentElement.clientHeight
const clientWidth = document.documentElement.clientWidth
switch (false) {
case (docHeight === lastDocHeight):
case (docWidth === lastDocWidth):
case (clientHeight === lastClientHeight):
case (clientWidth === lastClientWidth):
lastDocHeight = docHeight
lastDocWidth = docWidth
lastClientHeight = clientHeight
lastClientWidth = clientWidth
trigger()
}
}
animationFrame = window.requestAnimationFrame(loop)
}
/**
* Fire all callback functions in the callback collection
*/
function trigger() {
// Reverse while loop is safer when potentially removing elements from array
let i=callbackCollection.length
while(i--) {
// callback functions are external and could be problematic
const callback = callbackCollection[i]
try {
callback.func()
} catch (err) {
if (callback.breakOnError) {
removeResizeListener(callback.func)
} else {
// pass through error otherwise
throw err
}
}
}
}
/**
* Test if callback collection contains a reference to the supplied callback function
*
* @param {function} func The function to test for presence in the collection
* @return {boolean} true if found, false if not found
*/
function contains(func) {
return callbackCollection.length && callbackCollection.reduce((prev, callback) => {
prev || func === callback.func
}, false)
}
/**
* Binds a callback function to the resize listener
*
* @param {function} func The callback function to trigger on resize
* @param {boolean} breakOnError If callback function throws an error, remove from resize listener
*/
function addResizeListener(func, breakOnError = false) {
// Only allow a single instance of a callback function
if (!contains(func)) {
// Only allow functions as callbackCollection
if (typeof func === 'function') {
callbackCollection.push(new Callback(func, breakOnError))
}
}
}
/**
* Remove a callback function from the resize listener
*
* @param {function} func The callback function to remove from the resize listener
*/
function removeResizeListener(func) {
let i=callbackCollection.length
while(i--) {
if (callbackCollection[i].func === func) {
callbackCollection.splice(i, 1)
break
}
}
}
return { addResizeListener, removeResizeListener }
}
module.exports = resizeFrame()