-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
listeners.js
107 lines (79 loc) · 2.28 KB
/
listeners.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
const _ = require('lodash')
const HISTORY_ATTRS = 'pushState replaceState'.split(' ')
let events = []
let listenersAdded = null
const removeAllListeners = () => {
listenersAdded = false
for (let e of events) {
const [win, event, cb] = e
win.removeEventListener(event, cb)
}
// reset all the events
events = []
return null
}
const addListener = (win, event, cb) => {
events.push([win, event, cb])
win.addEventListener(event, cb)
}
const eventHasReturnValue = (e) => {
const val = e.returnValue
// return false if val is an empty string
// of if its undinefed
if (val === '' || _.isUndefined(val)) {
return false
}
// else return true
return true
}
module.exports = {
bindTo (contentWindow, callbacks = {}) {
if (listenersAdded) {
return
}
removeAllListeners()
listenersAdded = true
// set onerror global handler
contentWindow.onerror = callbacks.onError
addListener(contentWindow, 'beforeunload', (e) => {
// bail if we've canceled this event (from another source)
// or we've set a returnValue on the original event
if (e.defaultPrevented || eventHasReturnValue(e)) {
return
}
callbacks.onBeforeUnload(e)
})
addListener(contentWindow, 'unload', (e) => {
// when we unload we need to remove all of the event listeners
removeAllListeners()
// else we know to proceed onwards!
callbacks.onUnload(e)
})
addListener(contentWindow, 'hashchange', (e) => {
callbacks.onNavigation('hashchange', e)
})
for (let attr of HISTORY_ATTRS) {
const orig = contentWindow.history?.[attr]
if (!orig) {
continue
}
contentWindow.history[attr] = function (...args) {
orig.apply(this, args)
return callbacks.onNavigation(attr, args)
}
}
addListener(contentWindow, 'submit', (e) => {
// if we've prevented the default submit action
// without stopping propagation, we will still
// receive this event even though the form
// did not submit
if (e.defaultPrevented) {
return
}
// else we know to proceed onwards!
return callbacks.onSubmit(e)
})
contentWindow.alert = callbacks.onAlert
contentWindow.confirm = callbacks.onConfirm
},
}