Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save maple3142/c6593f0aff180bc0e4be5d549259da2c to your computer and use it in GitHub Desktop.

Select an option

Save maple3142/c6593f0aff180bc0e4be5d549259da2c to your computer and use it in GitHub Desktop.
polyfill of 'beforescriptexecute' event
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="onbeforescriptexecute.js"></script>
<script>
window.onbeforescriptexecute=e=>{
if(e.script.textContent.includes(`alert`)&&!e.script.textContent.includes('document')){
e.preventDefault()
}
}
</script>
<script>
alert('hello')
</script>
<script>
console.log('hello')
</script>
<script>
const el=document.createElement('script')
el.textContent=`
alert('1')
`
document.body.appendChild(el)
</script>
</body>
</html>
// polyfill of 'beforescriptexecute' event
// original version: https://gist.github.com/jspenguin2017/cd568a50128c71e515738413cd09a890
// add support for dynamic added script (only for textContent)
{
;('use strict')
const Event = class {
constructor(script, target) {
this.script = script
this.target = target
this._cancel = false
this._replace = null
this._stop = false
}
preventDefault() {
this._cancel = true
}
stopPropagation() {
this._stop = true
}
replacePayload(payload) {
this._replace = payload
}
}
let callbacks = []
window.addBeforeScriptExecuteListener = f => {
if (!f instanceof Function) {
throw new Error('Event handler must be a function.')
}
callbacks.push(f)
}
window.removeBeforeScriptExecuteListener = f => {
let i = callbacks.length
while (i--) {
if (callbacks[i] === f) {
callbacks.splice(i, 1)
}
}
}
const dispatch = (script, target) => {
if (script.tagName !== 'SCRIPT') {
return
}
const e = new Event(script, target)
if (window.onbeforescriptexecute instanceof Function) {
try {
window.onbeforescriptexecute(e)
} catch (err) {
console.error(err)
}
}
for (let i = 0; i < callbacks.length; i++) {
if (e._stop) {
break
}
try {
callbacks[i](e)
} catch (err) {
console.error(err)
}
}
if (e._cancel) {
script.remove()
} else if (typeof e._replace === 'string') {
script.textContent = e._replace
}
return e
}
const observer = new MutationObserver(mutations => {
for (let i = 0; i < mutations.length; i++) {
for (let j = 0; j < mutations[i].addedNodes.length; j++) {
dispatch(mutations[i].addedNodes[j], mutations[i].target)
}
}
})
observer.observe(document, {
childList: true,
subtree: true
})
Object.defineProperty(HTMLScriptElement.prototype, 'textContent', {
get() {
return this._ct || this.innerHTML
},
set(t) {
this._ct = t
const e = dispatch(this, this)
if (!e._cancel) {
this.innerHTML = t
} else if (typeof e._replace === 'string') {
this.innerHTML = e._replace
}
}
})
// Object.defineProperty(HTMLScriptElement.prototype, 'innerHTML', {
// get() {
// return this._ct || this.textContent
// },
// set(t) {
// this._ct = t
// const e = dispatch(this, this)
// if (!e._cancel) {
// this.textContent = t
// } else if (typeof e._replace === 'string') {
// this.textContent = e._replace
// }
// }
// })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment