您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Definable is a modular ModMenu for Drawaria.Online
当前为
// ==UserScript== // @name Definable ModMenu // @namespace Definable // @version 0.1.2 // @description Definable is a modular ModMenu for Drawaria.Online // @homepage https://drawaria.online/profile/?uid=63196790-c7da-11ec-8266-c399f90709b7 // @author ≺ᴄᴜʙᴇ³≻ // @match https://drawaria.online/ // @match https://drawaria.online/test // @match https://drawaria.online/room/* // @icon https://i.ibb.co/8Xb1gXg/Andrew-T-Austin-brightly-lit-tesseract-hypercube.png // @grant none // @license GNU GPLv3 // @run-at document-end // ==/UserScript== (() => { String.prototype.toFunction = function () { return new Function("(" + this + ")()"); }; String.prototype.__invokeAsFunction = function (...args) { new Function("(" + this + ")()")(); }; Function.prototype.callAsWorker = function (...args) { return new Promise((resolve, reject) => { const code = `self.onmessage = e => self.postMessage((${this.toString()}).call(null, ...e.data));`, blob = new Blob([code], { type: "text/javascript" }), worker = new Worker((window.URL ?? window.webkitURL).createObjectURL(blob)); worker.onmessage = (e) => (resolve(e.data), worker.terminate()); worker.onerror = (e) => (reject(e.message), worker.terminate()); worker.postMessage(args); }); }; const originalElementPrototypeAppend = Element.prototype.append; Element.prototype.append = function (...elements) { elements = elements.filter((appendingElement) => { if (appendingElement instanceof HTMLElement) return true; return false; }); originalElementPrototypeAppend.apply(this, elements); return this; }; // Function.toString().replace(/^\s*\/\/.+$/gm, "").split("\n").filter((s) => s).map((s) => s.trim()).join(""); })(); (async function ($name) { "use strict"; const cache = { storage: await caches.open($name), /** * @param {string} url * @param {string} scriptContent */ saveScript: function (url, scriptContent) { this.storage.put(url, new Response(scriptContent, { headers: { "Content-Type": "application/javascript" } })); }, /** * @param {string} url * @param {object} json */ saveObject: function (url, json) { this.storage.put(url, new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json" } })); }, /** * @param {string} url * @returns {Promise<string>} */ loadScript: async function (url) { const response = (await this.storage.match(url)) || (await fetch(url)); return await response.text(); }, /** * @param {string} url * @returns {Promise<object>} */ loadObject: async function (url) { const response = (await this.storage.match(url)) || (await fetch(url)); return await response.json(); }, }; const UI = { /** * Returns the first element that is a descendant of node that matches selectors. * @param {string} selectors * @param {ParentNode} parentElement * @returns {Element|null} */ querySelect: (selectors, parentElement = document) => parentElement.querySelector(selectors), /** * Returns all element descendants of node that match selectors. * @param {string} selectors * @param {ParentNode} parentElement * @returns {NodeListOf<Element>} */ querySelectAll: (selectors, parentElement = document) => parentElement.querySelectorAll(selectors), /** * Create Element and assign properties to it. * @param {string} tagName * @param {object} properties * @returns {Element} */ createElement: (tagName, properties = {}) => { /** @type {Element} */ const element = Object.assign(document.createElement(tagName), properties); if (properties.title) { try { element.setAttribute("data-toggle", "tooltip"); element.setAttribute("data-html", "true"); jQuery(element).tooltip({ boundary: "window" }); } catch (error) {} } return element; }, /** * Assign attributes to element. * @param {Element} element * @param {object} attributes */ setAttributes: (element, attributes) => Object.entries(attributes).forEach(([k, v]) => element.setAttribute(k, v)), /** * Assign styles to element. * @param {Element} element * @param {object} styles */ setStyles: (element, styles) => Object.assign(element.style, styles), /** * @param {string} name * @returns {HTMLDivElement} */ createContainer: function (name = "div") { return this.createElement(name, { className: "container" }); }, /** * @returns {HTMLDivElement} */ createRow: function () { return this.createElement("div", { className: "row" }); }, /** * @param {string} name * @returns {HTMLElement} */ createIcon: function (name) { return this.createElement("i", { className: `fas fa-${name}` }); }, /** * @param {string} type * @param {object} properties * @returns {HTMLInputElement} */ createInput: function (type, properties = {}) { const input = this.createElement("input", { ...{ className: "form-control" }, ...properties, ...{ type: type } }); if (!input.id) input.id = uid(8); return input; }, /** * @param {HTMLInputElement} input * @param {object} properties * @returns {HTMLLabelElement} */ createLabelFor: function (input, properties = {}) { const label = this.createElement("label", { ...{ className: "btn btn-sm btn-outline-secondary" }, ...properties, ...{ htmlFor: input.id } }); label.appendChild(input); input.hidden = true; if (input.type === "checkbox" || input.type === "radio") { input.addEventListener("input", function () { label.classList[input.checked ? "add" : "remove"]("active"); }); } return label; }, /** * @param {string} className * @returns {HTMLElement & { show: Function, hide: Function }} */ createSpinner: function (className = "text-secondary") { const spinner = this.createElement("div", { className: [className, "spinner-border spinner-border-sm"].join(" ") }); spinner.show = function () { spinner.classList.remove("d-none"); }; spinner.hide = function () { spinner.classList.add("d-none"); }; spinner.hide(); return spinner; }, /** * @param {HTMLInputElement} input * @param {HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement} addon * @returns {HTMLDivElement} */ createGroup: function (input, addon) { const group = this.createElement("div", { className: "input-group input-group-sm" }); const groupAppend = this.createElement("div", { className: "input-group-append" }); if (!(addon instanceof HTMLInputElement || addon instanceof HTMLButtonElement)) { addon.classList.add("input-group-text"); } groupAppend.appendChild(addon); group.appendChild(input); group.appendChild(groupAppend); return group; }, /** * @param {Array<HTMLLabelElement|HTMLInputElement|HTMLButtonElement|HTMLElement>} inputs * @returns {HTMLDivElement} */ createInputGroup: function (...inputs) { const group = this.createElement("div", { className: "input-group input-group-sm" }); let previousElementSibling = inputs[0]; let appendGroup = this.createElement("div", { className: "input-group-append" }); for (let index = 0; index < inputs.length; index++) { const input = inputs[index]; if (input instanceof HTMLInputElement) { if (!(previousElementSibling instanceof HTMLInputElement)) { group.appendChild(appendGroup); appendGroup = this.createElement("div", { className: "input-group-append" }); } input.hidden = false; group.appendChild(input); } else { input.classList.add("input-group-text"); appendGroup.appendChild(input); if (index + 1 === inputs.length) { group.appendChild(appendGroup); } } previousElementSibling = input; } return group; }, }; const DrawariaOnlineMessageTypes = { /** * @param {string} message * @returns {string} */ chatmsg: function (message) { // 42["chatmsg","a"] const data = ["chatmsg", message]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ passturn: function () { // 42["passturn"] const data = ["passturn"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ pgdrawvote: function (playerid) { // 42["pgdrawvote",2,0] const data = ["pgdrawvote", playerid, 0]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ pgswtichroom: function () { // 42["pgswtichroom"] const data = ["pgswtichroom"]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ playerafk: function () { // 42["playerafk"] const data = ["playerafk"]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ playerrated: function () { // 42["playerrated"] const data = ["playerrated"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} gestureid * @returns {string} */ sendgesture: function (gestureid) { // 42["sendgesture",16] const data = ["sendgesture", gestureid]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ sendvote: function () { // 42["sendvote"] const data = ["sendvote"]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ sendvotekick: function (playerid) { // 42["sendvotekick",93] const data = ["sendvotekick", playerid]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} wordid * @returns {string} */ wordselected: function (wordid) { // 42["wordselected",0] const data = ["sendvotekick", wordid]; return `${42}${JSON.stringify(data)}`; }, clientcmd: { /** * @param {number|string} itemid * @param {boolean} isactive * @returns {string} */ activateitem: function (itemid, isactive) { const data = ["clientcmd", 12, [itemid, isactive]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @returns {string} */ buyitem: function (itemid) { const data = ["clientcmd", 11, [itemid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {"zindex"|"shared"} target * @param {any} value * @returns {string} */ canvasobj_changeattr: function (itemid, target, value) { const data = ["clientcmd", 234, [itemid, target, value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ canvasobj_getobjects: function () { const data = ["clientcmd", 233]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @returns {string} */ canvasobj_remove: function (itemid) { let data = ["clientcmd", 232, [itemid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {number|string} positionX * @param {number|string} positionY * @param {number|string} speed * @returns {string} */ canvasobj_setposition: function (itemid, positionX, positionY, speed) { const data = ["clientcmd", 230, [itemid, 100 / positionX, 100 / positionY, { movespeed: speed }]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} itemid * @param {number|string} rotation * @returns {string} */ canvasobj_setrotation: function (itemid, rotation) { const data = ["clientcmd", 231, [itemid, rotation]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {any} value * @returns {string} */ customvoting_setvote: function (value) { const data = ["clientcmd", 301, [value]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {any} value * @returns {string} */ getfpid: function (value) { const data = ["clientcmd", 901, [value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ getinventory: function () { const data = ["clientcmd", 10, [true]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ getspawnsstate: function () { const data = ["clientcmd", 102]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} positionX * @param {number|string} positionY * @returns {string} */ moveavatar: function (positionX, positionY) { const data = ["clientcmd", 103, [1e4 * Math.floor(positionX * 0.01 * 1e4) + Math.floor(positionY * 0.01 * 1e4), false]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ setavatarprop: function () { const data = ["clientcmd", 115]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} flagid * @param {boolean} isactive * @returns {string} */ setstatusflag: function (flagid, isactive) { const data = ["clientcmd", 3, [flagid, isactive]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} tokenid * @returns {string} */ settoken: function (playerid, tokenid) { const data = ["clientcmd", 2, [playerid, tokenid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {any} value * @returns {string} */ snapchatmessage: function (playerid, value) { const data = ["clientcmd", 330, [playerid, value]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ spawnavatar: function () { const data = ["clientcmd", 101]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ startrollbackvoting: function () { const data = ["clientcmd", 320]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ trackforwardvoting: function () { const data = ["clientcmd", 321]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} trackid * @returns {string} */ votetrack: function (trackid) { const data = ["clientcmd", 1, [trackid]]; return `${42}${JSON.stringify(data)}`; }, }, /** * @param {string} roomID * @param {string} name * @param {string} uid * @param {string} wt * @returns {string} */ startplay: function (roomID, name = undefined, uid = undefined, wt = undefined) { const data = `${420}${JSON.stringify(["startplay", name, 2, "en", roomID, null, [null, "https://drawaria.online/", 1000, 1000, [null, uid, wt], null]])}`; return data; }, clientnotify: { /** * @param {number|string} playerid * @returns {string} */ requestcanvas: function (playerid) { const data = ["clientnotify", playerid, 10001]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} base64 * @returns {string} */ respondcanvas: function (playerid, base64) { const data = ["clientnotify", playerid, 10002, [base64]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} imageid * @returns {string} */ galleryupload: function (playerid, imageid) { const data = ["clientnotify", playerid, 11, [imageid]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {any} type * @returns {string} */ warning: function (playerid, type) { const data = ["clientnotify", playerid, 100, [type]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} targetname * @param {boolean} mute * @returns {string} */ mute: function (playerid, targetname, mute = false) { const data = ["clientnotify", playerid, 1, [mute, targetname]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} targetname * @param {boolean} hide * @returns {string} */ hide: function (playerid, targetname, hide = false) { const data = ["clientnotify", playerid, 3, [hide, targetname]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {string} reason * @param {string} targetname * @returns {string} */ report: function (playerid, reason, targetname) { const data = ["clientnotify", playerid, 2, [targetname, reason]]; return `${42}${JSON.stringify(data)}`; }, }, drawcmd: { /** * @param {number|string} playerid * @param {number|string} x1 * @param {number|string} y1 * @param {number|string} x2 * @param {number|string} y2 * @param {number|string} size * @param {number|string} color * @param {boolean} ispixel * @returns {string} */ line: function (x1, y1, x2, y2, color, size = 4, ispixel = true, playerid = 0) { const data = ["drawcmd", 0, [x1 * 0.001, y1 * 0.001, x2 * 0.001, y2 * 0.001, false, -size, color, playerid, ispixel]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @param {number|string} x1 * @param {number|string} y1 * @param {number|string} x2 * @param {number|string} y2 * @param {number|string} size * @param {number|string} color * @returns {string} */ erase: function (x1, y1, x2, y2, color, size, ispixel = true, playerid = 0) { const data = ["drawcmd", 1, [x1 * 0.01, y1 * 0.01, x2 * 0.01, y2 * 0.01, false, -size, color, playerid, ispixel]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} x * @param {number|string} y * @param {number|string} color * @param {number|string} tolerance * @param {number|string} r * @param {number|string} g * @param {number|string} b * @param {number|string} a * @returns {string} */ flood: function (x, y, color, tolerance, r, g, b, a) { // 42["drawcmd",2,[x, y,color,{"0":r,"1":g,"2":b,"3":a},size]] const data = ["drawcmd", 2, [x * 0.01, y * 0.01, color, { 0: r, 1: g, 2: b, 3: a }, tolerance]]; return `${42}${JSON.stringify(data)}`; }, /** * @param {number|string} playerid * @returns {string} */ undo: function (playerid) { // 42["drawcmd",3,[playerid]] const data = ["drawcmd", 3, [playerid]]; return `${42}${JSON.stringify(data)}`; }, /** * @returns {string} */ clear: function () { // 42["drawcmd",4,[]] const data = ["drawcmd", 4, []]; return `${42}${JSON.stringify(data)}`; }, }, }; /** * @param {string} message * @param {string} styles */ const log = (message, styles = "color:#5090C1", application = undefined) => console.log("%c" + [`[${application ?? $name}]`, message].join(" "), styles); /** * Generate radnow UID * @param {number} size * @returns {string} */ const uid = (size = 8) => { const MASK = 0x3d; const LETTERS = "abcdefghijklmnopqrstuvwxyz"; const NUMBERS = "1234567890"; const SPECIALS = "-_"; const charset = `${NUMBERS}${LETTERS}${LETTERS.toUpperCase()}${SPECIALS}`.split(""); const bytes = new Uint8Array(size); crypto.getRandomValues(bytes); return bytes.reduce((acc, byte) => `${acc}${charset[byte & MASK]}`, ""); }; /** * @param {number[]} byteArray * @returns {string} */ const toHexString = (byteArray) => { return byteArray.map((byte) => byte.toString(16).padStart(2, "0")).join(""); }; /** * @param {string} key * @param {string} value */ const setCookie = (key, value) => { if (window.Cookie) Cookies.set(key, value); document.cookie = `${key}=${value}; Secure; Path=/; SameSite=None; Partitioned;`; }; /** * @param {(index:number,value:*)=>{}} callbackOnDelete * @param {(index:number,value:*)=>{}} callbackOnSet * @returns {Array<*>} */ const makeObservableArray = (callbackOnDelete, callbackOnSet) => { if (!("Proxy" in window)) { console.warn("Your browser doesn't support Proxies."); return; } // a proxy for our array const proxy = new Proxy([], { deleteProperty: function (target, property) { (callbackOnDelete ?? ___)(property, target[property]); delete target[property]; return true; }, set: function (target, property, value, receiver) { target[property] = value; (callbackOnSet ?? ___)(property, value); return true; }, }); Object.defineProperty(proxy, "isProxy", { value: true, writable: false, }); return proxy; }; /** * @param {string} message * @returns {Array<any>|object} */ const tryParseJSON = (message) => { try { return JSON.parse(message); } catch (error) { return []; } }; const clearScripts = (remove = true) => { try { let array = document.querySelectorAll('script[src]:not([data-codemaid="ignore"])'); array.forEach((script) => { if (script.src != "") document.head.appendChild(script); }); } catch (error) { console.error(error); } try { let unifiedScript = DefinableCore.UI.createElement("script"); let scripts = document.querySelectorAll('script:not([src]):not([data-codemaid="ignore"])'); let unifiedScriptContent = ""; scripts.forEach((script) => { let content = script.textContent; //.replaceAll(/\s/g, ''); unifiedScriptContent += `try{${content}}catch(e){console.warn(e);}`; script.remove(); }); unifiedScript.textContent = unifiedScriptContent; if (!remove) document.head.appendChild(unifiedScript); } catch (error) { console.error(error); } }; const clearStyles = (remove = false) => { try { let unifiedStyles = DefinableCore.UI.createElement("style"); unifiedStyles.textContet = ""; let styles = document.querySelectorAll('style:not([data-codemaid="ignore"])'); styles.forEach((style) => { unifiedStyles.textContent += style.textContent; style.remove(); }); if (!remove) document.head.appendChild(unifiedStyles); } catch (error) { console.error(error); } }; const clearEmbeds = () => { try { let array = document.querySelectorAll("iframe"); array.forEach((iframe) => { iframe.remove(); }); } catch (error) { console.error(error); } }; class Player { /** @type {Array<Player>} */ static instances = []; static get noConflict() { return Player.instances[0] ?? new Player(uid(12)); } /** * @param {string|undefined} inviteLink * @returns {URL} */ static getSocketServerURL(inviteLink) { if (typeof inviteLink === "undefined") return `wss://sv3.drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`; const roomID = this.getRoomID(inviteLink); const [_voidable, serverPrefix] = roomID.split("."); return new URL(`wss://${typeof serverPrefix === "undefined" ? "" : "sv".concat(serverPrefix, ".")}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`); } /** * @param {string|undefined} inviteLink * @returns {string} */ static getRoomID(inviteLink) { const inviteURL = new URL(inviteLink); return inviteURL.pathname.slice(6); } static parseMessage = DrawariaOnlineMessageTypes; /** @type {string} */ name; /** @type {string} */ uid; /** @type {string} */ wt; /** @type {string} */ roomID; /** @type {WebSocket} */ socket; /** @type {Map<string, Function[]>} */ events; /** * @param {string} name */ constructor(name = undefined) { this.name = name; this.uid = "_"; this.wt = undefined; this.roomID = undefined; this.events = new Map(); Player.instances.push(this); } /** * @param {string} inviteLink */ connect = (inviteLink) => { if (this.isConnected) return; this.#createNewConnection(inviteLink); }; disconnect = () => { this.send("41"); if (this.isConnected) this.socket.close(); }; reconnect = () => { if (!this.isConnected) { this.connect(`https://drawaria.online/room/${this.roomID}`); return; } this.send("41"); this.send("40"); }; /** * @param {string} inviteLink */ enterRoom = (inviteLink = undefined) => { this.roomID = Player.getRoomID(inviteLink ?? document.querySelector("#invurl").value); this.reconnect(); }; nextRoom = () => { this.send(Player.parseMessage.pgswtichroom()); }; leaveRoom = () => { this.send("41"); }; /** * @param {string} payload */ send = (payload) => { if (this.isConnected) this.socket.send(payload); else debug(`send failed! Connection is closed`); }; /** * @returns {boolean} */ get isConnected() { return typeof this.socket !== "undefined" && this.socket instanceof WebSocket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING); } #sendHeartbeat = () => { if (this.isConnected) this.socket.send(2); }; /** * @param {string} inviteLink */ #createNewConnection = (inviteLink) => { this.socket = new WebSocket(Player.getSocketServerURL(inviteLink)); this.roomID = Player.getRoomID(inviteLink); this.socket.addEventListener("open", this.#startHeartbeat); this.socket.addEventListener("message", this.#handleMessage); }; #startHeartbeat = () => { this.heartbeatInterval = setInterval(this.#sendHeartbeat, 25000); }; #handleMessage = (rawMessage) => { const [eventType, eventName, eventData] = this.#parseMessageEvent(rawMessage); switch (eventType) { case "40": this.send(Player.parseMessage.startplay(this.roomID, this.name, this.uid, this.wt)); break; case "430": break; case "42": this.__invokeEvent(eventName, eventData); break; default: } }; /** * @param {MessageEvent} messageEvent * @returns {[string, string, Array<any>|object]} */ #parseMessageEvent = (messageEvent) => { const rawData = String(messageEvent.data); const messageType = (rawData.match(/^\d+/i) ?? [""])[0]; const messageData = messageType.length === rawData.length ? [] : tryParseJSON(rawData.slice(messageType.length)); return [messageType, Array.isArray(messageData) ? messageData.shift() : "", messageData]; }; /** * @param {DrawariaOnlineEvents} event * @param {Function} callback */ addEventListener = (event, callback, id = undefined) => { if (!this.hasEventListener(event)) { this.events.set(event, []); } callback.id = id ?? this.addEventListener.caller.name ?? uid(8); try { this.events.get(event).push(callback); } catch (error) { debug(`addEventListener returned error \"${error}\"`, "color:firebrick"); } }; /** * @param {DrawariaOnlineEvents} event * @param {*} data */ __invokeEvent = (event, data) => { if (this.hasEventListener(event)) { const listeners = this.events.get(event); listeners.forEach((listener) => listener(data)); } }; /** * @param {DrawariaOnlineEvents} name * @returns {boolean} */ hasEventListener = (name) => { return this.events.has(name); }; } class DefinableCore { static UI = UI; static Player = Player; constructor(moduleName, moduleIcon = "code") { this.name = moduleName; this.__initializeHead(moduleIcon); this.__initializeBody(); } __initializeHead(moduleIcon) { const input = this.UI.createInput("checkbox"); this.label = this.UI.createLabelFor(input, { title: this.name }); const icon = this.UI.createIcon(moduleIcon); this.label.appendChild(icon); } __initializeBody() { const submoduleSelectionContainer = this.UI.createElement("nav", { className: "row" }); const wrapper = this.UI.createElement("div"); this.wrapper = wrapper; this.__contaier = this.UI.createElement("div"); this.__contaier.appendChild(this.UI.createElement("b", { textContent: this.name })); // this.wrapper.appendChild(submoduleSelectionContainer); this.__contaier.appendChild(submoduleSelectionContainer); this.wrapper.appendChild(this.__contaier); const input = this.UI.querySelect("&>input", this.label); input.addEventListener("input", function () { wrapper.classList[input.checked ? "remove" : "add"]("d-none"); }); wrapper.classList.add("d-none"); } createRow() { const row = this.UI.createRow(); this.__contaier.appendChild(row); return row; } /** * @param {DefinableCore} submodule */ registerModule(submodule) { // const submoduleSelectionContainer = this.UI.querySelect("&>nav", this.wrapper); const submoduleSelectionContainer = this.UI.querySelect("&>nav", this.__contaier); submoduleSelectionContainer.appendChild(submodule.label); this.wrapper.appendChild(submodule.wrapper); } get UI() { return DefinableCore.UI; } get Player() { return DefinableCore.Player; } } window.addEventListener("definable:core:init", function () { const ui = DefinableCore.UI; const definable = new DefinableCore("Definable", "code"); const chatbox = ui.querySelect("#chatbox_messages"); /** @type {HTMLElement} */ const devider = chatbox.previousElementSibling; devider.before(definable.wrapper); definable.wrapper.before(devider.cloneNode(false)); setTimeout(() => { window.dispatchEvent(new CustomEvent("definable:init", { detail: { main: definable, core: DefinableCore } })); definable.wrapper.classList.remove("d-none"); definable.wrapper.classList.add("container"); definable.wrapper.id = "definable"; }, 500); }); setTimeout(() => { window.dispatchEvent(new CustomEvent("definable:core:init")); clearEmbeds(); clearScripts(); clearStyles(); document.head.appendChild( UI.createElement("style", { id: "definableStyles", textContent: ["#definable .row { gap: 0.125rem; margin-bottom: 0.125rem; }", "#definable label { margin: 0; }"].join("\n") }) ); // console.clear(); }, 500); function launchScriptManager() { const ui = DefinableCore.UI; const container = ui.createContainer(); { const row = ui.createRow(); const scriptSourceLinkInput = ui.createInput("text", { className: "form-control" }); const requestSourceInput = ui.createInput("button"); const requestSourceLabel = ui.createLabelFor(requestSourceInput); const group = ui.createGroup(scriptSourceLinkInput, requestSourceLabel); const spinnerIcon = ui.createSpinner(""); const defaultIcon = ui.createIcon("external-link-alt"); requestSourceLabel.appendChild(defaultIcon); requestSourceLabel.appendChild(spinnerIcon); requestSourceInput.addEventListener("click", function () { defaultIcon.classList.add("d-none"); spinnerIcon.show(); if (!scriptSourceLinkInput.value.startsWith("http")) { log("Not a valid Link: ".concat(scriptSourceLinkInput.value), "color: firebrick;"); spinnerIcon.hide(); defaultIcon.classList.remove("d-none"); return; } const requestSourceLink = new URL(scriptSourceLinkInput.value); log("Requesting Module: ".concat(requestSourceLink), "color: rebeccapurple;"); fetch(requestSourceLink).then(async (response) => { const copy = response.clone(); const content = await copy.text(); if (copy.status === 200 && content) { cache.saveScript(requestSourceLink, content); log("Module installed!", "color: forestgreen;"); spinnerIcon.hide(); defaultIcon.classList.remove("d-none"); scriptSourceLinkInput.value = ""; } }); }); row.appendChild(group); container.appendChild(row); } DefinableCore.UI.querySelect("#login-leftcol").appendChild(container); } })("definable");