Base64编码解码

为水源恢复Base64解码和编码

// ==UserScript==
// @name         Base64编码解码
// @namespace    http://tampermonkey.net/
// @version      0.0.2
// @description  为水源恢复Base64解码和编码
// @author       艾伦·走路人 & Rosmontis
// @match        https://shuiyuan.sjtu.edu.cn/*
// @license      WTFPL
// @grant none
// ==/UserScript==

// 创建观察者实例
const observer = new MutationObserver((mutationsList) => {
  for (const mutation of mutationsList) {
    if (mutation.type === "childList") {
      const list = document.querySelector(
        ".toolbar-popup-menu-options .select-kit-collection"
      );
      if (list) {
        let encodeIcon = document.createElementNS(
          "http://www.w3.org/2000/svg",
          "use"
        );
        encodeIcon.setAttribute("href", "#far-eye-slash");
        let base64EncodeIcon = encodeIcon.outerHTML;
        addButtonToList(
          list,
          "base64-encode",
          base64EncodeIcon,
          "Base64编码",
          encode
        );
        let decodeIcon = document.createElementNS(
          "http://www.w3.org/2000/svg",
          "use"
        );
        decodeIcon.setAttribute("href", "#far-eye");
        let base64DecodeIcon = decodeIcon.outerHTML;
        addButtonToList(
          list,
          "base64-decode",
          base64DecodeIcon,
          "Base64解码",
          decode
        );
      }
    }
  }
});

// 开始观察文档的子节点变化
observer.observe(document.body, { childList: true, subtree: true });

// 添加按钮的函数
function addButtonToList(list, id, icon, text, action) {
  // 检查按钮是否已经存在
  if (!list.querySelector('li[data-guid="' + id + '"]')) {
    // 创建新的li元素
    const newItem = document.createElement("li");
    newItem.setAttribute("data-guid", id);
    newItem.setAttribute("role", "menuitemradio");
    newItem.setAttribute("tabindex", "0");
    newItem.classList.add("select-kit-row", "dropdown-select-box-row");

    // 添加图标
    const iconDiv = document.createElement("div");
    iconDiv.classList.add("icons");
    const iconSvg = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    iconSvg.classList.add("fa", "d-icon", "svg-icon", "svg-string");
    iconSvg.innerHTML = icon;
    iconDiv.appendChild(iconSvg);
    newItem.appendChild(iconDiv);

    // 添加文字
    const textDiv = document.createElement("div");
    textDiv.classList.add("texts");
    const textSpan = document.createElement("span");
    textSpan.classList.add("name");
    textSpan.textContent = text;
    textDiv.appendChild(textSpan);
    newItem.appendChild(textDiv);

    // 添加点击事件
    newItem.addEventListener("click", () => {
      // 获取当前的 textarea
      let textarea = document.querySelector("textarea");
      let start = textarea.selectionStart;
      let end = textarea.selectionEnd;
      let selectedText = textarea.value.substring(start, end);
      let newText = action(selectedText);
      textarea.value =
        textarea.value.substring(0, start) +
        newText +
        textarea.value.substring(end);
      simulateTypeAndDelete(textarea);
      textarea.selectionStart = start;
      textarea.selectionEnd = start + newText.length;
    });

    // 将新元素添加到列表中
    list.appendChild(newItem);
  }
}

function encode(str) {
  return btoa(encodeURIComponent(str));
}

function decode(base64) {
  return decodeURIComponent(atob(base64));
}

function simulateTypeAndDelete(textareaElement) {
  // 将 textarea 设置为焦点
  textareaElement.focus();

  // 模拟输入 '0'
  let inputEvent = new InputEvent("input", {
    bubbles: true,
    cancelable: true,
    inputType: "insertText",
    data: "0",
  });

  // 创建一个键盘事件,模拟按下 '0' 键
  let keydownEvent = new KeyboardEvent("keydown", {
    key: "0",
    keyCode: 48,
    which: 48,
    bubbles: true,
    cancelable: true,
  });

  // 派发键盘事件和输入事件,模拟输入 '0'
  textareaElement.dispatchEvent(keydownEvent);
  textareaElement.dispatchEvent(inputEvent);

  // 模拟 Backspace 键盘事件
  let backspaceEvent = new KeyboardEvent("keydown", {
    key: "Backspace",
    keyCode: 8,
    which: 8,
    bubbles: true,
    cancelable: true,
  });

  // 派发 Backspace 键盘事件
  textareaElement.dispatchEvent(backspaceEvent);
}