linux.do.level

Linux.Do 查看用户信任级别以及升级条件,数据来源于 https://connect.linux.do

Verze ze dne 03. 06. 2024. Zobrazit nejnovější verzi.

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         linux.do.level
// @namespace    https://linux.do/u/io.oi/s/level
// @version      1.3.0
// @author       LINUX.DO
// @description  Linux.Do 查看用户信任级别以及升级条件,数据来源于 https://connect.linux.do
// @license      MIT
// @icon         https://cdn.linux.do/uploads/default/original/1X/de7ee26820e897b6a07350126411ebc489f62202.png
// @match        https://linux.do/*
// @connect      connect.linux.do
// @grant        GM.xmlHttpRequest
// @grant        GM_addStyle
// ==/UserScript==

(e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const o=document.createElement("style");o.textContent=e,document.head.append(o)})(" .level-window{position:fixed;bottom:0;background:var(--secondary);z-index:999;padding:.5em;color:var(--primary);box-shadow:0 0 4px #00000020;border:1px solid var(--primary-low)}.level-window .title .close{width:30px;height:30px;color:#fff;background:red;display:inline-block;text-align:center;line-height:30px;float:right;cursor:pointer;border-radius:4px}.level-window .bg-white{background-color:var(--primary-50);border-radius:.5em;padding:.5em;margin-top:.5em}.level-window h1{color:var(--primary);font-size:1.3rem}.level-window h2{font-size:1.25rem}.mb-4 table tr:nth-child(2n){background-color:var(--tertiary-400)}.level-window .text-red-500{color:#ef4444}.level-window .text-green-500{color:#10b981}.level-window .mb-4 table tr td{padding:4px 8px} ");

(function () {
  'use strict';

  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => {
    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
    return value;
  };
  function showMessageBox(message, title, buttons = [
    {
      text: "确认",
      type: "btn-primary",
      onClicked: function() {
      }
    }
  ]) {
    let root = document.querySelector("div.modal-container");
    if (root) {
      let box = document.createElement("div");
      box.id = "message-box";
      box.className = "ember-view modal d-modal discard-draft-modal";
      box.setAttribute("data-keyboard", "false");
      box.setAttribute("aria-modal", "true");
      box.setAttribute("role", "dialog");
      box.innerHTML = `
        <div class="d-modal__container">
            <div class="d-modal__header">${title}</div>
            <div class="d-modal__body" tabindex="-1">
              <div class="instructions">
              ${message}
              </div>
            </div>
            <div class="d-modal__footer">
            </div>
        </div>`;
      let backdrop = document.createElement("div");
      backdrop.className = "d-modal__backdrop";
      root.appendChild(backdrop);
      let footer = box.querySelector("div.d-modal__footer");
      if (footer) {
        for (const button of buttons) {
          let btnElement = document.createElement("button");
          btnElement.className = "btn btn-text " + button.type;
          btnElement.setAttribute("type", "button");
          btnElement.innerHTML = `
               <span class="d-button-label">
                    ${button.text}
               </span>
            `;
          btnElement.addEventListener("click", () => {
            button.onClicked();
            box.remove();
            backdrop.remove();
          });
          footer.appendChild(btnElement);
        }
        root.appendChild(box);
      }
    }
  }
  function observeDom(selector, onChanged, option) {
    let dom = document.querySelector(selector);
    if (dom) {
      const observer = new MutationObserver(() => {
        onChanged(dom);
      });
      observer.observe(dom, option ? option : { childList: true });
      return observer;
    } else {
      console.error(`query dom error: [${selector}]`);
      return null;
    }
  }
  function isOnTopicPage() {
    return window.location.href.includes("https://linux.do/t/topic");
  }
  const _DomEventBus = class _DomEventBus {
    constructor() {
      __publicField(this, "listenerMap");
      __publicField(this, "observeMap");
      this.listenerMap = {};
      this.observeMap = {};
    }
    static getInstance() {
      if (!this.instance) {
        this.instance = new _DomEventBus();
      }
      return this.instance;
    }
    add(name, listener) {
      if (!this.listenerMap[name]) {
        this.listenerMap[name] = [];
      }
      if (this.listenerMap[name].length === 0) {
        let observe = observeDom(name, () => {
          this.domEmit(name);
        });
        if (observe) {
          this.observeMap[name] = observe;
        }
      }
      this.listenerMap[name].push(listener);
    }
    domEmit(event) {
      const listeners = this.listenerMap[event];
      if (listeners) {
        for (const listener of listeners) {
          listener();
        }
      }
    }
    clear(name) {
      if (!this.listenerMap[name]) {
        return;
      }
      this.listenerMap[name] = [];
    }
  };
  __publicField(_DomEventBus, "instance");
  let DomEventBus = _DomEventBus;
  class Invite {
    fixInviteAnchors(container) {
      const selector = 'a[href^="https://linux.do/invites/"]';
      let anchors = Array.from(container ? container.querySelectorAll(selector) : document.querySelectorAll(selector));
      for (const anchor of anchors) {
        const inviteUrl = anchor.href;
        anchor.href = "javascript:void(0);";
        anchor.onclick = null;
        let buttons = [
          {
            text: "我就是想被下限",
            type: "btn-danger",
            onClicked: () => {
              window.location.href = inviteUrl;
            }
          },
          {
            text: "差点就不干净了",
            type: "",
            onClicked: () => {
            }
          }
        ];
        anchor.addEventListener("click", () => {
          showMessageBox("这是一个邀请连接,虽然你已经注册,但是跳转后,你仍会成为邀请人的下线。", "警告", buttons);
        });
      }
    }
    observeMainOutlet() {
      let observe = null;
      DomEventBus.getInstance().add("div#main-outlet", () => {
        if (isOnTopicPage()) {
          this.fixInviteAnchors();
          observe = observeDom("div#main-outlet div.container.posts div.row div.ember-view", (dom) => {
            this.fixInviteAnchors(dom);
          });
        } else {
          observe == null ? void 0 : observe.disconnect();
        }
      });
    }
    init() {
      this.fixInviteAnchors();
      this.observeMainOutlet();
    }
  }
  var _GM = /* @__PURE__ */ (() => typeof GM != "undefined" ? GM : void 0)();
  async function getLevelFromConnect() {
    return await new Promise((resolve, reject) => {
      _GM.xmlHttpRequest({
        method: "GET",
        url: "https://connect.linux.do",
        onload: (response) => {
          let regx = /<body[^>]*>([\s\S]+?)<\/body>/i;
          let contents = regx.exec(response.responseText);
          if (contents) {
            const content = contents[1].replace('<a href="/logout" target="_self" class="text-blue-500 hover:underline" title="LINUX DO登录也会退出">退出</a>', "");
            resolve({
              status: true,
              content,
              error: ""
            });
          }
        },
        onerror: (e) => {
          reject({ status: false, error: e.error, content: "" });
        }
      });
    });
  }
  function createWindow(content, onClose) {
    let root = document.createElement("div");
    root.setAttribute("id", "level-window");
    root.className = "level-window";
    root.style.right = document.querySelector("div.chat-drawer.is-expanded") ? "430px" : "15px";
    root.innerHTML = `
     <div class="title">
         <span class="close" id="close-button">
              <svg class="fa d-icon d-icon-times svg-icon svg-string" xmlns="http://www.w3.org/2000/svg">
                  <use href="#times"></use>
              </svg>
         </span>
         <div id="content" class="content"></div>
     </div>`;
    let container = root.querySelector("div#content");
    if (container) {
      container.innerHTML = content;
    }
    let close = root.querySelector("span#close-button");
    close == null ? void 0 : close.addEventListener("click", onClose);
    DomEventBus.getInstance().add("div.chat-drawer-outlet-container", () => {
      let chat = document.querySelector("div.chat-drawer.is-expanded");
      root.style.right = chat ? "430px" : "15px";
    });
    let chatContainer = document.querySelector("div.chat-drawer-outlet-container");
    if (chatContainer) {
      let observer = new MutationObserver((_) => {
        let chat = document.querySelector("div.chat-drawer.is-expanded");
        root.style.right = chat ? "430px" : "15px";
      });
      observer.observe(chatContainer, { childList: true });
    }
    return root;
  }
  function getLoadingSvg(size = 60) {
    return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}px" height="${size}px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-ring">
              <circle cx="50" cy="50" r="30" stroke="#B3B5B411" stroke-width="10" fill="none"/>
              <circle cx="50" cy="50" r="30" stroke="#808281" stroke-width="10" fill="none" transform="rotate(144 50 50)">
                <animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"/>
                <animate attributeName="stroke-dasharray" calcMode="linear" values="18.84955592153876 169.64600329384882;94.2477796076938 94.24777960769377;18.84955592153876 169.64600329384882" keyTimes="0;0.5;1" dur="1" begin="0s" repeatCount="indefinite"/>
              </circle> 
            </svg>`;
  }
  class Level {
    constructor() {
      __publicField(this, "levelWindow");
      __publicField(this, "loading", false);
    }
    init() {
      this.replaceConnectAnchor();
    }
    replaceConnectAnchor() {
      let connectAnchor = document.querySelector('a[href="https://connect.linux.do"]');
      if (connectAnchor) {
        connectAnchor.href = "javascript:void(0);";
        connectAnchor.addEventListener("click", async () => {
          if (!this.loading && this.levelWindow === void 0) {
            this.loading = true;
            let icon = connectAnchor.querySelector("span.sidebar-section-link-prefix.icon");
            if (icon) {
              let defaultIcon = icon.innerHTML;
              icon.innerHTML = getLoadingSvg();
              let result = await getLevelFromConnect();
              this.loading = false;
              icon.innerHTML = defaultIcon;
              if (result.status) {
                this.levelWindow = createWindow(result.content, () => {
                  var _a;
                  (_a = this.levelWindow) == null ? void 0 : _a.remove();
                  this.levelWindow = void 0;
                });
                document.body.appendChild(this.levelWindow);
              } else {
                console.error(result.error);
              }
            }
          } else {
            this.levelWindow.remove();
            this.levelWindow = void 0;
          }
        });
        return;
      }
      console.error("replace connect anchor error.");
    }
  }
  function createFloor(num) {
    let button = document.createElement("button");
    button.className = "widget-button btn-flat reply create fade-out btn-icon-text";
    button.setAttribute("title", `${num}楼`);
    button.setAttribute("id", "floor-button");
    button.innerHTML = `<span class='d-button-label'>${num}楼</span>`;
    return button;
  }
  class Floor {
    constructor() {
      __publicField(this, "eventBus");
      this.eventBus = DomEventBus.getInstance();
    }
    observeUrl() {
      const changed = () => {
        if (isOnTopicPage()) {
          this.eventBus.add("div.container.posts section.topic-area div.ember-view", () => {
            if (isOnTopicPage()) {
              this.fixFloorDom();
            }
          });
          this.fixFloorDom();
        } else {
          this.eventBus.clear("div.container.posts section.topic-area div.ember-view");
        }
      };
      this.eventBus.add("div#main-outlet", changed);
    }
    fixFloorDom() {
      var _a;
      let floors = Array.from(document.body.querySelectorAll("div.container.posts section.topic-area div.ember-view div.topic-post.clearfix.regular"));
      for (const floor of floors) {
        if (floor.querySelector("button#floor-button")) {
          continue;
        }
        let article = floor.querySelector("article");
        if (article) {
          let id = (_a = article.getAttribute("id")) == null ? void 0 : _a.replace("post_", "");
          let actions = floor.querySelector("article section nav div.actions");
          actions == null ? void 0 : actions.appendChild(createFloor(id ? id : "??"));
        }
      }
    }
    init() {
      this.observeUrl();
    }
  }
  function init() {
    window.addEventListener("load", () => {
      new Level().init();
      new Invite().init();
      new Floor().init();
    });
  }
  init();

})();