InjectJS

Inject Javascript into almost any website.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name             InjectJS
// @namespace        http://github.com/YTXaos/InjectJS
// @version          1.30
// @description      Inject Javascript into almost any website.
// @description:es   Inyecte Javascript en casi cualquier sitio web
// @description:fr   Injectez Javascript dans presque tous les sites Web
// @description:de   Fügen Sie Javascript in fast jede Website ein
// @description:ja   ほぼすべてのウェブサイトにジャバスクリとを挿入する
// @description:la   Javascript in inject paene omnem website
// @description:ru   Внедрите Javascript практически в любой веб-сайт
// @author           YTXaos
// @match            *://*/*
// @match            file:///*
// @icon             https://raw.githubusercontent.com/YTXaos/InjectJS/main/assets/logo.png
// @grant            GM_addElement
// @grant            GM_getResourceText
// @grant            GM_getResourceURL
// @license          MIT
// @require          https://code.jquery.com/jquery-3.6.0.min.js
// @resource         MainCSS https://raw.githubusercontent.com/YTXaos/InjectJS/main/assets/main.css
// @resource         OptionsHTML https://raw.githubusercontent.com/YTXaos/InjectJS/main/pages/options.html
// @resource         OptionsJS https://raw.githubusercontent.com/YTXaos/InjectJS/main/options.js
// @resource         Fontawesome https://raw.githubusercontent.com/YTXaos/InjectJS/main/assets/fontawesome.css
// @resource         MainIcon https://raw.githubusercontent.com/YTXaos/InjectJS/main/assets/logov2.png
// ==/UserScript==

(function() {
    "use strict";
    const url = location.href,
        origin = location.origin;
    /**
     * @param {string} item Specify what item to look for in the options.
     * @returns {string} True or false if found, false boolean if not.
     */
    function Option(item) {
        if(localStorage.getItem(`inject-js:${item}`)) {
            return localStorage.getItem(`inject-js:${item}`).toString();
        } else {
            return false;
        }
    }
    /**
     * Create a log node.
     * @param {string} type The type of log to create.
     * @param {string} msg The message to output in the logs.
     */
    function createLog(type, msg) {
        const elm = document.querySelector(".js-injector-logs");
        let msg_type;
        type === "warning" && (msg_type = "WARN") || (msg_type = type.toUpperCase());
        elm.innerHTML += `
        <div class="js-log ${type}">
            [InjectJS&nbsp;<span class="time-date"></span>&nbsp;${msg_type}]:&nbsp;
            <span class="js-log-message">
                ${msg}
            </span>
        </div>`;
    }
    const logs = {
        info(msg) { createLog("info", msg); },
        warn(msg) { createLog("warning", msg); },
        error(msg) { createLog("error", msg); }
    }
    /**
     * Check whether the page the user is on is equivalent to param "page".
     * @param {string} page Specify what URL to check for.
     * @param {boolean} exact Whether it should check for the exact URL or relative.
     * @returns {boolean} True or false
     */
    function onURL(page, exact) {
        if(exact) {
            return url === `${origin}${page}`;
        } else {
            return url.includes(page);
        }
    }
    if(Option("disable") == "true") {
        document.addEventListener("keyup", function(e) {
            e.preventDefault();
            if(e.ctrlKey && e.key === ".") {
                localStorage.setItem("inject-js:disable", false);
                location.reload();
            }
        });
        return;
    }
    if(onURL("/inject-js/", true)) {
        location = "https://github.com/YTXaos/InjectJS";
    }
    Option("startup_log") == "true" && (console.info("InjectJS Loaded. Press Ctrl + Q to topen"));
    const popup = document.createElement("div"),
        log = document.createElement("div");
    GM_addElement(document.head, "style", { textContent: GM_getResourceText("MainCSS") });
    log.setAttribute("class", "js-injector-logs");
    log.innerHTML = '<span class="js-logs-close" title="Close" id="js-close">&times;</span>';
    log.style.display = "none";
    popup.setAttribute("class", "js-injector-popup");
    popup.style.display = "none";
    popup.innerHTML = `<label class="js-inject-header">
    <div class="js-logo-needle" style="background-image: url(${GM_getResourceURL("MainIcon")})">.....</div>
    Inject<span class="js-logo">JS</span>
</label>
<textarea placeholder="Your code here" class="js-code-inject" spellcheck="false" data-gramm="false" data-gramm_editor="false" data-enable-grammarly="false" id="js-code-inject"></textarea>
<div class="js-btns-section">
<button class="execute-code" disabled>Execute</button>
<button class="js-options-btn">Options</button>
</div>
<div class="js-btns-column">
<button class="show-js-logs">Logs</button>
</div>`;
    document.body.append(log);
    document.body.prepend(popup);

    function OptionsPage() {
        $("link[rel=stylesheet], style, script").remove();
        document.title = "InjectJS Options";
        document.body.innerHTML = GM_getResourceText("OptionsHTML");
        GM_addElement(document.head, "script", { textContent: GM_getResourceText("OptionsJS") });
    }
    const code = document.querySelector(".js-code-inject"),
        btn = document.querySelector(".execute-code"), option_btn = document.querySelector(".js-options-btn"), log_btn = document.querySelector(".show-js-logs");
    code.addEventListener("input", CheckCode);
    log_btn.addEventListener("click", function() {
        document.querySelector(".js-injector-logs").setAttribute("style", "display: flex !important");
        document.getElementById("js-close").addEventListener("click", function() {
            document.querySelector(".js-injector-logs").setAttribute("style", "");
        });
    });
    if(Option("disable_syntax") != "true") { code.addEventListener("keydown", Syntax); }
    btn.addEventListener("click", InjectCode);
    option_btn.addEventListener("click", () => { location = "/inject-js/options"; });
    /**
     * Syntax properties for autocomplete "(", "{", and strings.
     * @param {event} e Returns an event to handle accordingly.
     */
    function Syntax(e) {
        if(e.key === "{") {
            e.preventDefault();
            const start = code.selectionStart,
              end = code.selectionEnd,
              selection = code.value.substring(start, end),
              replace = `${code.value.substring(0, start)}{\n${selection}\n}${code.value.substring(end)}`;
            code.value = replace;
            code.focus();
            code.selectionEnd = end + 2;
          }
          if(e.key === "(") {
            e.preventDefault();
            const start = code.selectionStart,
              end = code.selectionEnd,
              selection = code.value.substring(start, end),
              replace = `${code.value.substring(0, start)}(${selection})${code.value.substring(end)}`;
            code.value = replace;
            code.focus();
            code.selectionEnd = end + 1;
          }
          if(e.which === 222) {
            e.preventDefault();
            const start = code.selectionStart,
              end = code.selectionEnd,
              selection = code.value.substring(start, end),
              replace = `${code.value.substring(0, start)}${e.key}${selection}${e.key}${code.value.substring(end)}`;
            code.value = replace;
            code.focus();
            code.selectionEnd = end + 1;
          }
    }
    function CheckCode() {
        const code = document.querySelector(".js-code-inject");
        if(code.value.length < 5) {
            btn.setAttribute("disabled", "disabled");
        } else {
            btn.removeAttribute("disabled");
        }
    }

    function InjectCode() {
        try {
            eval(code.value);
        } catch (e) {
            if(Option("alert_errors") == "true") {
                alert(e.message);
            } else {
                logs.error(e);
            }
        }
    }

    function ShowInjector() {
        dragElement(document.querySelector(".js-injector-popup"));
        /**
         * Makes an elemenet draggable around the screen.
         * @param {string} elmnt Select an element from the DOM to become draggable
         */
        function dragElement(elmnt) {
            var pos1 = 0,
                pos2 = 0,
                pos3 = 0,
                pos4 = 0;
            if(document.querySelector(".js-inject-header")) {
                document.querySelector(".js-inject-header").onmousedown = dragMouseDown;
            } else {
                elmnt.onmousedown = dragMouseDown;
            }

            function dragMouseDown(e) {
                e = e || window.event;
                e.preventDefault();
                pos3 = e.clientX;
                pos4 = e.clientY;
                document.onmouseup = closeDragElement;
                document.onmousemove = elementDrag;
            }

            function elementDrag(e) {
                e = e || window.event;
                e.preventDefault();
                pos1 = pos3 - e.clientX;
                pos2 = pos4 - e.clientY;
                pos3 = e.clientX;
                pos4 = e.clientY;
                elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
                elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
            }

            function closeDragElement() {
                document.onmouseup = null;
                document.onmousemove = null;
            }
        }
        popup.classList.toggle("show");
    }
    if(onURL("/inject-js/options", true)) {
        OptionsPage();
    }
    document.addEventListener("keyup", function(e) {
        e.preventDefault();
        if(e.ctrlKey && e.key === "q") {
            ShowInjector();
        }
    });
})();