-
-
Save luccabb/31d6ba45766ab385770dc8e392716dbc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(() => { | |
"use strict"; | |
var t = { | |
79: (t, e) => { | |
const n = ["#docs-editor-container"], | |
o = ["#docs-editor", ...n], | |
r = ["iframe.docs-texteventtarget-iframe", ".docs-texteventtarget-iframe"], | |
i = [".kix-page", ".docs-page"], | |
s = [".kix-lineview", ".kix-paragraphrenderer"], | |
c = [".kix-lineview-text-block"], | |
a = [".kix-wordhtmlgenerator-word-node"], | |
l = [".kix-selection-overlay"], | |
u = [".kix-cursor"], | |
d = [".docs-text-ui-cursor-blink"], | |
f = [".kix-cursor-caret"]; | |
function h(t, e = document) { | |
if (null == e) throw new Error("Passed root element does not exists"); | |
let n = null; | |
for (const o of t) | |
if (n = e.querySelector(o), n) break; | |
return n | |
} | |
function p(t, e = document) { | |
if (null == e) throw new Error("Passed root element does not exists"); | |
let n = null; | |
for (const o of t) | |
if (n = e.querySelectorAll(o), n.length > 0) break; | |
return n ? Array.from(n) : [] | |
} | |
function m() { | |
return h(o) | |
} | |
function y(t, e) { | |
const n = document.createElement("span"); | |
n.textContent = t, n.style.cssText = e, n.style.whiteSpace = "pre", n.style.position = "absolute", n.style.top = "-100px", document.body.appendChild(n); | |
const o = n.getBoundingClientRect(); | |
return n.remove(), o | |
} | |
function g() { | |
const t = h(r); | |
return function(t) { | |
return "iframe" === t.nodeName.toLowerCase() | |
}(t) ? t.contentDocument : t | |
} | |
function w() { | |
const t = m(); | |
return p(i, t) | |
} | |
function v() { | |
const t = w(); | |
let e = []; | |
for (const n of t) { | |
const t = p(s, n); | |
e = [...e, ...t] | |
} | |
return e | |
} | |
function x() { | |
const t = v(), | |
e = []; | |
for (const n of t) { | |
const t = h(c, n); | |
e.push(t) | |
} | |
return e | |
} | |
function K(t) { | |
return function(t) { | |
return t.replace(/\u00A0/g, "") | |
}(t = t.replace(/\u200C/g, "")) | |
} | |
function E() { | |
const t = x(), | |
e = []; | |
for (const n of t) { | |
let t = n.textContent; | |
t = K(t), t = b(t), e.push(t) | |
} | |
return e | |
} | |
function b(t) { | |
return t.trim() | |
} | |
function A() { | |
const t = v(), | |
e = []; | |
for (const n of t) { | |
const t = p(a, n); | |
e.push(t) | |
} | |
return e | |
} | |
function C() { | |
const t = v(), | |
e = []; | |
for (const n of t) { | |
const t = h(l, n); | |
e.push(t) | |
} | |
return e | |
} | |
function P(t, e, n, o) { | |
let r = n.left, | |
i = !1, | |
s = 0, | |
c = t.length; | |
for (let n = 0; n !== t.length; n++) { | |
if (o.left <= r && r < o.right) i || (s = n, i = !0); | |
else if (i) { | |
c = n; | |
break | |
} | |
r += y(t[n], e) | |
.width | |
} | |
return i ? { | |
start: s, | |
end: c | |
} : null | |
} | |
function L() { | |
const t = m(); | |
return h(u, t) | |
} | |
function k() { | |
const t = m(); | |
return h(d, t) | |
} | |
function S() { | |
const t = L(); | |
return t ? h(f, t) : null | |
} | |
function R() { | |
const t = S(); | |
if (!t) return null; | |
const e = A(); | |
if (!e.length) return null; | |
const n = t.getBoundingClientRect(), | |
o = { | |
element: null, | |
wordElement: null, | |
lineIndex: null, | |
positionIndexRelativeToWord: null | |
}; | |
let r = !1; | |
for (let c = 0; c !== e.length; c++) { | |
const a = e[c]; | |
for (let e = 0; e !== a.length; e++) { | |
const l = a[e], | |
u = l.getBoundingClientRect(); | |
if (s = u, (i = n) | |
.left <= s.right && i.right >= s.left && i.top <= s.bottom && i.bottom >= s.top) { | |
o.element = t, o.wordElement = l, o.lineIndex = c, o.positionIndexRelativeToWord = D(u, n, l.textContent, l.style.cssText), r = !0; | |
break | |
} | |
} | |
if (r) break | |
} | |
var i, s; | |
return o | |
} | |
function D(t, e, n, o) { | |
let r = t.left - e.width, | |
i = 0; | |
for (const t of n) { | |
const n = y(t, o); | |
if (0 !== n.width) { | |
if (r += n.width, r >= e.left) break; | |
i += 1 | |
} | |
} | |
return i | |
} | |
function I(t, e, n) { | |
let o, r, i; | |
n ? (o = t => t <= 0, r = t => t - 1, i = t => t + 1) : (o = t => t >= e.length, r = t => t + 1, i = t => t - 1); | |
let s = t, | |
c = e[s]; | |
if (n && T(c) && !o(s) && (s = r(s), c = e[s], T(c))) return t; | |
for (; !T(c) && !o(s);) s = r(s), c = e[s]; | |
return n && !o(s) && (s = i(s)), s | |
} | |
function T(t) { | |
return null == t || !((e = t) | |
.match(/[\w]/) || e.toLowerCase() !== e.toUpperCase()); | |
var e | |
} | |
function M(t, e, n, o, r, i) { | |
return null == o && (o = "Key" + n.toUpperCase()), null == r && (r = n.codePointAt(0)), new KeyboardEvent(t, { | |
repeat: !1, | |
isComposing: !1, | |
bubbles: !0, | |
cancelable: !0, | |
ctrlKey: !1, | |
shiftKey: !1, | |
altKey: !1, | |
metaKey: !1, | |
target: e, | |
currentTarget: e, | |
key: n, | |
code: o, | |
keyCode: r, | |
charCode: r, | |
which: r, | |
...i | |
}) | |
} | |
function N(t, e, n = null, o = null, r = {}) { | |
const i = M("keypress", t, e, n, o, r); | |
t.dispatchEvent(i) | |
} | |
function B(t, e, n = null, o = null, r = {}) { | |
const i = M("keydown", t, e, n, o, r); | |
t.dispatchEvent(i) | |
} | |
function _(t, { | |
ctrlKey: e = !1, | |
shiftKey: n = !1 | |
} = {}) { | |
e || n ? B(g(), t, null, null, { | |
ctrlKey: e, | |
shiftKey: n | |
}) : N(g(), t) | |
} | |
function O({ | |
ctrlKey: t = !1 | |
} = {}) { | |
B(g(), "Backspace", "Backspace", 8, { | |
ctrlKey: t | |
}) | |
} | |
function H({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "End", "End", 35, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function W({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "Home", "Home", 36, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function F({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "ArrowLeft", "ArrowLeft", 37, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function U({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "ArrowUp", "ArrowUp", 38, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function q({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "ArrowRight", "ArrowRight", 39, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function j({ | |
ctrlKey: t = !1, | |
shiftKey: e = !1 | |
} = {}) { | |
B(g(), "ArrowDown", "ArrowDown", 40, { | |
ctrlKey: t, | |
shiftKey: e | |
}) | |
} | |
function z({ | |
ctrlKey: t = !1 | |
} = {}) { | |
B(g(), "Delete", "Delete", 46, { | |
ctrlKey: t | |
}) | |
} | |
function V() { | |
_("z", { | |
ctrlKey: !0 | |
}) | |
} | |
var $ = Object.freeze({ | |
__proto__: null, | |
Character: _, | |
Backspace: O, | |
Tab: function() { | |
B(g(), "Tab", "Tab", 9) | |
}, | |
Enter: function() { | |
B(g(), "Enter", "Enter", 13) | |
}, | |
Space: function() { | |
N(g(), " ", "Space", 32) | |
}, | |
End: H, | |
Home: W, | |
ArrowLeft: F, | |
ArrowUp: U, | |
ArrowRight: q, | |
ArrowDown: j, | |
Delete: z, | |
Undo: V, | |
Redo: function() { | |
_("y", { | |
ctrlKey: !0 | |
}) | |
}, | |
PrintDialog: function() { | |
_("p", { | |
ctrlKey: !0 | |
}) | |
}, | |
Bold: function() { | |
_("b", { | |
ctrlKey: !0 | |
}) | |
}, | |
Italic: function() { | |
_("i", { | |
ctrlKey: !0 | |
}) | |
}, | |
Underline: function() { | |
_("u", { | |
ctrlKey: !0 | |
}) | |
} | |
}); | |
function G() { | |
return C() | |
.some((t => !!t)) | |
} | |
function J() { | |
return !!k() | |
} | |
function Q() { | |
if (J()) return !1; | |
const t = G(); | |
return _("?"), t ? V() : O(), !0 | |
} | |
var X = Object.freeze({ | |
__proto__: null, | |
PrevCharacter: function() { | |
F() | |
}, | |
NextCharacter: function() { | |
q() | |
}, | |
PrevLine: function() { | |
U() | |
}, | |
NextLine: function() { | |
j() | |
}, | |
PrevWord: function() { | |
F({ | |
ctrlKey: !0 | |
}) | |
}, | |
NextWord: function() { | |
q({ | |
ctrlKey: !0 | |
}) | |
}, | |
PrevParagraph: function() { | |
U({ | |
ctrlKey: !0 | |
}) | |
}, | |
NextParagraph: function() { | |
j({ | |
ctrlKey: !0 | |
}) | |
}, | |
LineStart: function() { | |
Q(), W() | |
}, | |
LineEnd: function() { | |
Q(), H() | |
}, | |
DocumentStart: function() { | |
W({ | |
ctrlKey: !0 | |
}) | |
}, | |
DocumentEnd: function() { | |
H({ | |
ctrlKey: !0 | |
}) | |
} | |
}), | |
Y = Object.freeze({ | |
__proto__: null, | |
PrevWord: function() { | |
O({ | |
ctrlKey: !0 | |
}) | |
}, | |
NextWord: function() { | |
z({ | |
ctrlKey: !0 | |
}) | |
}, | |
Selection: function() { | |
return !!G() && (z(), !0) | |
} | |
}), | |
Z = Object.freeze({ | |
__proto__: null, | |
All: function() { | |
_("a", { | |
ctrlKey: !0 | |
}) | |
}, | |
PrevCharacter: function() { | |
F({ | |
shiftKey: !0 | |
}) | |
}, | |
NextCharacter: function() { | |
q({ | |
shiftKey: !0 | |
}) | |
}, | |
PrevWord: function() { | |
F({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
}, | |
NextWord: function() { | |
q({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
}, | |
PrevLine: function() { | |
Q(), U({ | |
shiftKey: !0 | |
}) | |
}, | |
NextLine: function() { | |
Q(), j({ | |
shiftKey: !0 | |
}) | |
}, | |
PrevParagraph: function() { | |
U({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
}, | |
NextParagraph: function() { | |
j({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
}, | |
TextBetweenCursorAndLineStart: function() { | |
Q(), W({ | |
shiftKey: !0 | |
}) | |
}, | |
TextBetweenCursorAndLineEnd: function() { | |
Q(), H({ | |
shiftKey: !0 | |
}) | |
}, | |
TextBetweenCursorAndDocumentStart: function() { | |
W({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
}, | |
TextBetweenCursorAndDocumentEnd: function() { | |
H({ | |
shiftKey: !0, | |
ctrlKey: !0 | |
}) | |
} | |
}); | |
const tt = {}, | |
et = function(t) { | |
const e = []; | |
for (let n of t) { | |
n.startsWith(".") || (n = n.slice(n.indexOf("."))), n = n.slice(1); | |
const t = n.split("."); | |
for (const n of t) n && e.push(n) | |
} | |
return e | |
}(l); | |
function nt(t) { | |
let e = !1; | |
for (const n of t) { | |
for (const t of n.addedNodes) { | |
const n = Array.from(t.classList || []); | |
e = e || et.some((t => n.includes(t))) | |
} | |
for (const t of n.removedNodes) { | |
const n = Array.from(t.classList || []); | |
e = e || et.some((t => n.includes(t))) | |
} | |
} | |
e && function(t) { | |
const e = tt[t]; | |
if (e) | |
for (const n of e) try { | |
n({ | |
type: t | |
}) | |
} catch (t) { | |
console.error(t) | |
} | |
}("selectionchange") | |
}! function(t) { | |
const e = () => { | |
t() | |
}; | |
"loading" === document.readyState ? document.addEventListener("DOMContentLoaded", e) : e() | |
}((function() { | |
const t = h(n); | |
if (null == t) throw new Error("Unable to observe missing docsEditorContainer"); | |
new MutationObserver(nt) | |
.observe(t, { | |
subtree: !0, | |
childList: !0, | |
attributes: !1, | |
characterData: !1 | |
}) | |
})), e.pressOn = $, e.typeText = function(t) { | |
! function(t) { | |
for (const e of t) _(e) | |
}(t) | |
} | |
}, | |
774: (t, e, n) => { | |
t.exports = n(79) | |
} | |
}, | |
e = {}; | |
function n(o) { | |
var r = e[o]; | |
if (void 0 !== r) return r.exports; | |
var i = e[o] = { | |
exports: {} | |
}; | |
return t[o](i, i.exports, n), i.exports | |
}(() => { | |
const t = async t => new Promise((e => { | |
chrome.storage.sync.get("excludeList", (n => { | |
let o = n.excludeList || []; | |
e(o.includes(t)) | |
})) | |
})), e = t => { | |
try { | |
return new URL(t) | |
?.host ?? "" | |
} catch (t) { | |
return console.log("Something went wrong", t), "" | |
} | |
}; | |
var o = n(774); | |
(() => { | |
const n = e(window.location.href); | |
chrome.runtime.onMessage.addListener(((t, e, o) => ("getHostByTabId" === t && o({ | |
host: n | |
}), !0))), window.addEventListener("load", (async function() { | |
await t(n) ? window.dispatchEvent(new CustomEvent("unloadScript")) : window.dispatchEvent(new CustomEvent("loadScript")) | |
})), chrome.storage.onChanged.addListener(((t, e) => { | |
"sync" === e && t.excludeList && (t.excludeList.newValue.includes(n) ? window.dispatchEvent(new CustomEvent("unloadScript")) : window.dispatchEvent(new CustomEvent("loadScript"))) | |
})) | |
})(); | |
const r = new class { | |
constructor(t, e = 5) { | |
this.textContainer = document.querySelector(".docs-texteventtarget-iframe") | |
.contentDocument.activeElement, this.gEditor = document.querySelector("#docs-editor"), this.pattern = t, this.deleteSpeed = e, this.handleKeyDown = this.handleKeyDown.bind(this) | |
} | |
activate() { | |
this.textContainer.addEventListener("keydown", this.handleKeyDown) | |
} | |
deactivate() { | |
this.textContainer.removeEventListener("keydown", this.handleKeyDown) | |
} | |
async handleKeyDown(t) { | |
if (this.initAuthOnPatternTyped(t), "Enter" === t.key) { | |
const e = document.querySelector("#kix-current-user-cursor-caret") | |
.getBoundingClientRect(), | |
n = Math.floor(e.right), | |
r = Math.floor(e.top), | |
i = this.getRect(n, r), | |
{ | |
patternFound: s, | |
prompt: c | |
} = this.extractPrompt(i, n, r, this.pattern); | |
if (s) { | |
t.preventDefault(), t.stopPropagation(), console.log(c), this.initFetchingResponseFromApi(c); | |
let e = c.length + this.pattern.length; | |
for (; e > 0;) o.pressOn.Backspace({ | |
ctrlKey: !1 | |
}), e--, await new Promise((t => setTimeout(t, this.deleteSpeed))); | |
await this.getResponseFromBgAndInsert(t.target) | |
} | |
} | |
} | |
initAuthOnPatternTyped(t) { | |
this.pattern.startsWith(this.typedPattern + t.key) ? (this.typedPattern += t.key, this.typedPattern === this.pattern && (console.log("********Pattern detected!**********"), this.initAuthenticationProcess(), this.typedPattern = "")) : this.typedPattern = "" | |
} | |
async initAuthenticationProcess() { | |
return console.log("1. Init Authentication Process"), new Promise(((t, e) => { | |
this.port = chrome.runtime.connect({ | |
name: "contentScript" | |
}), this.authenticationInProgress = !0, this.port.postMessage({ | |
msg: "initAuthentication" | |
}), this.port.onMessage.addListener((e => { | |
"authenticated" === e.msg && !0 === e.status && (console.log("2. Authenticated"), this.authenticated = !0, t(!0)) | |
})) | |
})) | |
} | |
async initFetchingResponseFromApi(t) { | |
this.authenticated || (this.authenticationInProgress ? (console.log("Authentication in progress. Waiting for a maximum of 10 secs..."), await new Promise(((t, e) => { | |
let n = 0; | |
const o = setInterval((() => { | |
n += 1e3, this.authenticated ? (clearInterval(o), t()) : n >= 1e4 && (clearInterval(o), e(new Error("Authentication timeout"))) | |
}), 1e3) | |
}))) : (console.log("Start a new authentication"), this.authenticated = await this.initAuthenticationProcess())), console.log("3. Init fetching response"), this.port.postMessage({ | |
msg: "fetchResponse", | |
prompt: t | |
}), this.authenticated = !1, this.authenticationInProgress = !1 | |
} | |
async getResponseFromBgAndInsert(t) { | |
console.log("hereee"); | |
console.log("o", o); | |
console.log("open gdocs and type '>> write about x' then press enter or return; observe 'test text' gets written"); | |
(0, o.typeText)("test text") | |
// this.port.postMessage({ | |
// msg: "startStreaming" | |
// }), this.isLoading(!0), this.lockMouse(!0), this.messageListener = async t => { | |
// console.log("hereee"); | |
// "streamData" === t.msg ? (0, o.typeText)(t.data) : "streamEnd" === t.msg && (this.isLoading(!1), this.lockMouse(!1), this.port.onMessage.removeListener(this.messageListener)) | |
// }, this.port.onMessage.addListener(this.messageListener) | |
} | |
getRect(t, e) { | |
if (!this.styleElement) { | |
this.styleElement = document.createElement("style"), this.styleElement.id = "enable-pointer-events-on-rect", this.styleElement.textContent = [".kix-canvas-tile-content{pointer-events:none!important;}", "#kix-current-user-cursor-caret{pointer-events:none!important;}", ".kix-canvas-tile-content svg>g>rect{pointer-events:all!important; stroke-width:7px !important;}"].join("\n"); | |
const t = document.head || document.documentElement; | |
null !== t && t.appendChild(this.styleElement) | |
} | |
this.styleElement.disabled = !1; | |
const n = document.elementFromPoint(t, e); | |
return this.styleElement.disabled = !0, n | |
} | |
getCaretIndex(t, e, n) { | |
const o = t.getAttribute("aria-label"), | |
r = document.createTextNode(o), | |
i = this.createTextOverlay(t, o, r); | |
if (!o || !i || !r) return null; | |
let s = document.createRange(), | |
c = 0, | |
a = r.nodeValue.length; | |
for (; a - c > 1;) { | |
const t = Math.floor((c + a) / 2); | |
s.setStart(r, t), s.setEnd(r, a); | |
const o = s.getClientRects(); | |
this.isPointInAnyRect(e, n, o) ? c = t : e > s.getClientRects()[0].right ? c = a : a = t | |
} | |
const l = c; | |
return i.remove(), l | |
} | |
extractPrompt(t, e, n, o, r = !0) { | |
let i = t, | |
s = "", | |
c = !1; | |
for (; i && "rect" === i.tagName;) { | |
const t = i.getAttribute("aria-label"), | |
a = t.indexOf(o); | |
if (a >= 0) { | |
if (r) { | |
const r = this.getCaretIndex(i, e, n); | |
s = t.substring(a + o.length, r) | |
} else s = t.substring(a + o.length) + " " + s; | |
c = !0; | |
break | |
} | |
if (r) { | |
const o = this.getCaretIndex(i, e, n); | |
s = t.substring(0, o) + s, r = !1 | |
} else s = t + " " + s; | |
i = i.previousElementSibling | |
} | |
if (!c) { | |
const i = t.parentNode.previousElementSibling; | |
if (i && "g" === i.tagName) { | |
const t = this.extractPrompt(i.lastElementChild, e, n, o, r); | |
t.prompt && (s = t.prompt + (s ? "\n" + s : ""), c = t.patternFound) | |
} | |
} | |
return { | |
patternFound: c, | |
prompt: s | |
} | |
} | |
isLoading(t) { | |
if (t) { | |
console.log("Added loading effect"); | |
const t = document.querySelector("#ChromeExtAiAnytime") || document.head.appendChild(document.createElement("style")); | |
t.id = "ChromeExtAiAnytime", t.textContent = "*{cursor:progress !important;}" | |
} else { | |
console.log("Removed loading effect"); | |
const t = document.querySelector("#ChromeExtAiAnytime"); | |
t && t.remove() | |
} | |
} | |
mouseHandler(t) { | |
t.preventDefault(), t.stopPropagation() | |
} | |
lockMouse(t) { | |
t ? (this.gEditor.addEventListener("mousemove", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.addEventListener("mousedown", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.addEventListener("mouseup", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.addEventListener("click", this.mouseHandler, { | |
capture: !0 | |
}), console.log("mouse locked")) : (this.gEditor.removeEventListener("mousemove", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.removeEventListener("mousedown", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.removeEventListener("mouseup", this.mouseHandler, { | |
capture: !0 | |
}), this.gEditor.removeEventListener("click", this.mouseHandler, { | |
capture: !0 | |
}), console.log("mouse unlocked")) | |
} | |
createTextOverlay(t, e, n) { | |
if (!t || "rect" !== t.tagName) return {}; | |
const o = document.createElementNS("http://www.w3.org/2000/svg", "text"), | |
r = t.getAttribute("transform") || "", | |
i = t.getAttribute("data-font-css") || ""; | |
o.setAttribute("x", t.getAttribute("x")), o.setAttribute("y", t.getAttribute("y")), o.appendChild(n), o.style.setProperty("all", "initial", "important"), o.style.setProperty("transform", r, "important"), o.style.setProperty("font", i, "important"), o.style.setProperty("text-anchor", "start", "important"), t.parentNode.appendChild(o); | |
const s = t.getBoundingClientRect(), | |
c = o.getBoundingClientRect(), | |
a = .5 * (s.top - c.top + (s.bottom - c.bottom)); | |
return o.style.setProperty("transform", `translate(0px,${a}px) ${r}`, "important"), o | |
} | |
isPointInAnyRect(t, e, n) { | |
for (const o of n) | |
if (t >= Math.floor(o.left) && t <= Math.floor(o.right) && e >= Math.floor(o.top) && e <= Math.floor(o.bottom)) return !0; | |
return !1 | |
} | |
}(">>", 5); | |
window.addEventListener("loadScript", (() => { | |
r.activate() | |
})), window.addEventListener("unloadScript", (() => { | |
r.deactivate() | |
})) | |
})() | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment