Greasy Fork

字体渲染(自用脚本)

让每个页面的字体变得有质感,默认使用苹方字体,附加字体描边、字体阴影、字体平滑等效果,自用脚本不处理外部需求。

目前为 2021-06-20 提交的版本。查看 最新版本

/* jshint esversion: 8 */
// ==UserScript==
// @name            字体渲染(自用脚本)
// @namespace       https://openuserjs.org/users/t3xtf0rm4tgmail.com
// @version         2021.06.20.6
// @icon            https://img.icons8.com/ios-filled/50/26e07f/font-style-formatting.png
// @description     让每个页面的字体变得有质感,默认使用苹方字体,附加字体描边、字体阴影、字体平滑等效果,自用脚本不处理外部需求。
// @supportURL      https://github.com/F9y4ng/GreasyFork-Scripts/issues
// @author          F9y4ng
// @include         *
// @grant           GM_info
// @grant           GM_registerMenuCommand
// @grant           GM.registerMenuCommand
// @grant           GM_unregisterMenuCommand
// @grant           GM_getValue
// @grant           GM.getValue
// @grant           GM_setValue
// @grant           GM.setValue
// @compatible      Chrome 兼容TamperMonkey, ViolentMonkey
// @compatible      Firefox 兼容Greasemonkey, TamperMonkey, ViolentMonkey
// @compatible      Opera 兼容TamperMonkey, ViolentMonkey
// @compatible      Safari 兼容Tampermonkey • Safari
// @license         GPL-3.0-only
// @create          2020-11-24
// @copyright       2020-2021, F9y4ng
// @run-at          document-start
// ==/UserScript==

!(function () {
  "use strict";

  /* customize */

  const isdebug = false; // set "true" to debug scripts, May cause script response slower.

  /* Perfectly Compatible For Greasemonkey4.0+, TamperMonkey, ViolentMonkey * F9y4ng * 20210609 */

  let GMsetValue, GMgetValue, GMregisterMenuCommand, GMunregisterMenuCommand;
  const GMinfo = GM_info;
  const handlerInfo = GMinfo.scriptHandler;
  const isGM = Boolean(handlerInfo.toLowerCase() === "greasemonkey");
  const debug = isdebug ? console.log.bind(console) : () => {};
  const error = isdebug ? console.error.bind(console) : () => {};
  const defCon = {
    scriptName: GMinfo.script.name,
    supportURL: GMinfo.script.supportURL,
    randString: (n, v, r, s = "") => {
      // v: true for only letters.
      let a = "0123456789";
      let b = "abcdefghijklmnopqrstuvwxyz";
      let c = b.toUpperCase();
      n = Number.isFinite(n) ? n : 10;
      v ? (r = b + c) : (r = a + b + a + c);
      for (; n > 0; --n) {
        s += r[Math.floor(Math.random() * r.length)];
      }
      return s;
    },
  };
  defCon.rndClass = defCon.randString(10, true);
  defCon.rndId = defCon.randString(12, true);

  if (isGM) {
    GMsetValue = GM.setValue;
    GMgetValue = GM.getValue;
    GMregisterMenuCommand = GM.registerMenuCommand;
    GMunregisterMenuCommand = () => {};
  } else {
    GMsetValue = GM_setValue;
    GMgetValue = GM_getValue;
    GMregisterMenuCommand = GM_registerMenuCommand;
    GMunregisterMenuCommand = GM_unregisterMenuCommand;
  }

  /* Color Picker init */

  ~(function (window, document) {
    let type = window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML";
    let picker;
    let slide;
    let hueOffset = 15;
    let svgNS = "http://www.w3.org/2000/svg";

    let colorpickerHTMLSnippet = [
      '<div class="picker-wrapper">',
      '<div class="picker"></div>',
      '<div class="picker-indicator"></div>',
      "</div>",
      '<div class="slide-wrapper">',
      '<div class="slide"></div>',
      '<div class="slide-indicator"></div>',
      "</div>",
    ].join("");

    function mousePosition(evt) {
      if (window.event && window.event.contentOverflow !== undefined) {
        return { x: window.event.offsetX, y: window.event.offsetY };
      }
      if (evt.offsetX !== undefined && evt.offsetY !== undefined) {
        return { x: evt.offsetX, y: evt.offsetY };
      }
      let wrapper = evt.target.parentNode.parentNode;
      return { x: evt.layerX - wrapper.offsetLeft, y: evt.layerY - wrapper.offsetTop };
    }

    function $(el, attrs, children) {
      el = document.createElementNS(svgNS, el);
      for (let key in attrs) {
        el.setAttribute(key, attrs[key]);
      }
      if (Object.prototype.toString.call(children) !== "[object Array]") {
        children = [children];
      }
      let i = 0;
      let len = (children[0] && children.length) || 0;
      for (; i < len; i++) {
        el.appendChild(children[i]);
      }
      return el;
    }

    if (type === "SVG") {
      slide = $("svg", { xmlns: "http://www.w3.org/2000/svg", version: "1.1", width: "100%", height: "100%" }, [
        $(
          "defs",
          {},
          $(
            "linearGradient",
            {
              id: "gradient-hsv",
              x1: "0%",
              y1: "100%",
              x2: "0%",
              y2: "0%",
            },
            [
              $("stop", { offset: "0%", "stop-color": "#FF0000", "stop-opacity": "1" }),
              $("stop", { offset: "13%", "stop-color": "#FF00FF", "stop-opacity": "1" }),
              $("stop", { offset: "25%", "stop-color": "#8000FF", "stop-opacity": "1" }),
              $("stop", { offset: "38%", "stop-color": "#0040FF", "stop-opacity": "1" }),
              $("stop", { offset: "50%", "stop-color": "#00FFFF", "stop-opacity": "1" }),
              $("stop", { offset: "63%", "stop-color": "#00FF40", "stop-opacity": "1" }),
              $("stop", { offset: "75%", "stop-color": "#0BED00", "stop-opacity": "1" }),
              $("stop", { offset: "88%", "stop-color": "#FFFF00", "stop-opacity": "1" }),
              $("stop", { offset: "100%", "stop-color": "#FF0000", "stop-opacity": "1" }),
            ]
          )
        ),
        $("rect", {
          x: "0",
          y: "0",
          width: "100%",
          height: "100%",
          fill: "url(#gradient-hsv)",
        }),
      ]);

      picker = $("svg", { xmlns: "http://www.w3.org/2000/svg", version: "1.1", width: "100%", height: "100%" }, [
        $("defs", {}, [
          $(
            "linearGradient",
            {
              id: "gradient-black",
              x1: "0%",
              y1: "100%",
              x2: "0%",
              y2: "0%",
            },
            [
              $("stop", { offset: "0%", "stop-color": "#000000", "stop-opacity": "1" }),
              $("stop", { offset: "100%", "stop-color": "#CC9A81", "stop-opacity": "0" }),
            ]
          ),
          $(
            "linearGradient",
            {
              id: "gradient-white",
              x1: "0%",
              y1: "100%",
              x2: "100%",
              y2: "100%",
            },
            [
              $("stop", { offset: "0%", "stop-color": "#FFFFFF", "stop-opacity": "1" }),
              $("stop", { offset: "100%", "stop-color": "#CC9A81", "stop-opacity": "0" }),
            ]
          ),
        ]),
        $("rect", {
          x: "0",
          y: "0",
          width: "100%",
          height: "100%",
          fill: "url(#gradient-white)",
        }),
        $("rect", {
          x: "0",
          y: "0",
          width: "100%",
          height: "100%",
          fill: "url(#gradient-black)",
        }),
      ]);
    } else if (type === "VML") {
      slide = [
        '<DIV style="position: relative; width: 100%; height: 100%">',
        '<v:rect style="position: absolute; top: 0; left: 0; width: 100%; height: 100%" stroked="f" filled="t">',
        '<v:fill type="gradient" method="none" angle="0" color="red" color2="red" colors="8519f fuchsia;.25 #8000ff;24903f #0040ff;.5 aqua;41287f #00ff40;.75 #0bed00;57671f yellow"></v:fill>',
        "</v:rect>",
        "</DIV>",
      ].join("");

      picker = [
        '<DIV style="position: relative; width: 100%; height: 100%">',
        '<v:rect style="position: absolute; left: -1px; top: -1px; width: 101%; height: 101%" stroked="f" filled="t">',
        '<v:fill type="gradient" method="none" angle="270" color="#FFFFFF" opacity="100%" color2="#CC9A81" o:opacity2="0%"></v:fill>',
        "</v:rect>",
        '<v:rect style="position: absolute; left: 0px; top: 0px; width: 100%; height: 101%" stroked="f" filled="t">',
        '<v:fill type="gradient" method="none" angle="0" color="#000000" opacity="100%" color2="#CC9A81" o:opacity2="0%"></v:fill>',
        "</v:rect>",
        "</DIV>",
      ].join("");

      if (!document.namespaces.v) {
        document.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML");
      }
    }

    function hsv2rgb(hsv) {
      let R, G, B, X, C;
      let h = (hsv.h % 360) / 60;

      C = hsv.v * hsv.s;
      X = C * (1 - Math.abs((h % 2) - 1));
      R = G = B = hsv.v - C;

      h = ~~h;
      R += [C, X, 0, 0, X, C][h];
      G += [X, C, C, X, 0, 0][h];
      B += [0, 0, X, C, C, X][h];

      let r = Math.floor(R * 255);
      let g = Math.floor(G * 255);
      let b = Math.floor(B * 255);
      return { r: r, g: g, b: b, hex: "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1) };
    }

    function rgb2hsv(rgb) {
      let r = rgb.r;
      let g = rgb.g;
      let b = rgb.b;

      if (rgb.r > 1 || rgb.g > 1 || rgb.b > 1) {
        r /= 255;
        g /= 255;
        b /= 255;
      }

      let H, S, V, C;
      V = Math.max(r, g, b);
      C = V - Math.min(r, g, b);
      H = C === 0 ? null : V === r ? (g - b) / C + (g < b ? 6 : 0) : V === g ? (b - r) / C + 2 : (r - g) / C + 4;
      H = (H % 6) * 60;
      S = C === 0 ? 0 : C / V;
      return { h: H, s: S, v: V };
    }

    function slideListener(ctx, slideElement, pickerElement) {
      return function (evt) {
        evt = evt || window.event;
        evt.stopPropagation();
        let mouse = mousePosition(evt);
        ctx.h = (mouse.y / slideElement.offsetHeight) * 360 + hueOffset;
        ctx.s = ctx.v = 1;
        let c = hsv2rgb({ h: ctx.h, s: 1, v: 1 });
        pickerElement.style.backgroundColor = c.hex;
        ctx.callback && ctx.callback(c.hex, { h: ctx.h - hueOffset, s: ctx.s, v: ctx.v }, { r: c.r, g: c.g, b: c.b }, undefined, mouse);
      };
    }

    function pickerListener(ctx, pickerElement) {
      return function (evt) {
        evt = evt || window.event;
        let mouse = mousePosition(evt);
        let width = pickerElement.offsetWidth;
        let height = pickerElement.offsetHeight;

        ctx.s = mouse.x / width;
        ctx.v = (height - mouse.y) / height;
        let c = hsv2rgb(ctx);
        ctx.callback && ctx.callback(c.hex, { h: ctx.h - hueOffset, s: ctx.s, v: ctx.v }, { r: c.r, g: c.g, b: c.b }, mouse);
      };
    }

    let uniqID = 0;

    class ColorPicker {
      constructor(slideElement, pickerElement, callback) {
        // new ColorPicker(slideElement, pickerElement, callback)
        this.h = 0;
        this.s = 1;
        this.v = 1;

        if (!callback) {
          let element = slideElement;
          element.innerHTML = colorpickerHTMLSnippet;

          this.slideElement = element.getElementsByClassName("slide")[0];
          this.pickerElement = element.getElementsByClassName("picker")[0];
          let slideIndicator = element.getElementsByClassName("slide-indicator")[0];
          let pickerIndicator = element.getElementsByClassName("picker-indicator")[0];

          ColorPicker.fixIndicators(slideIndicator, pickerIndicator);

          this.callback = function (hex, hsv, rgb, pickerCoordinate, slideCoordinate) {
            ColorPicker.positionIndicators(slideIndicator, pickerIndicator, slideCoordinate, pickerCoordinate);

            pickerElement(hex, hsv, rgb);
          };
        } else {
          this.callback = callback;
          this.pickerElement = pickerElement;
          this.slideElement = slideElement;
        }

        if (type === "SVG") {
          let hsvGradient = slide.getElementsByTagName("linearGradient")[0];
          let hsvRect = slide.getElementsByTagName("rect")[0];

          hsvGradient.id = "gradient-hsv-" + uniqID;
          hsvRect.setAttribute("fill", "url(#" + hsvGradient.id + ")");

          let blackAndWhiteGradients = picker.getElementsByTagName("linearGradient");
          let whiteAndBlackRects = picker.getElementsByTagName("rect");

          blackAndWhiteGradients[0].id = "gradient-black-" + uniqID;
          blackAndWhiteGradients[1].id = "gradient-white-" + uniqID;

          whiteAndBlackRects[0].setAttribute("fill", "url(#" + blackAndWhiteGradients[1].id + ")");
          whiteAndBlackRects[1].setAttribute("fill", "url(#" + blackAndWhiteGradients[0].id + ")");

          this.slideElement.appendChild(slide.cloneNode(true));
          this.pickerElement.appendChild(picker.cloneNode(true));

          uniqID++;
        } else {
          this.slideElement.innerHTML = slide;
          this.pickerElement.innerHTML = picker;
        }

        addEventListener(this.slideElement, "click", slideListener(this, this.slideElement, this.pickerElement));
        addEventListener(this.pickerElement, "click", pickerListener(this, this.pickerElement));

        enableDragging(this, this.slideElement, slideListener(this, this.slideElement, this.pickerElement));
        enableDragging(this, this.pickerElement, pickerListener(this, this.pickerElement));
      }
      setHsv(hsv) {
        return setColor(this, hsv);
      }
      setRgb(rgb) {
        return setColor(this, rgb2hsv(rgb), rgb);
      }
      setHex(hex) {
        return setColor(this, ColorPicker.hex2hsv(hex), undefined, hex);
      }
      static hsv2rgb(hsv) {
        let rgbHex = hsv2rgb(hsv);
        delete rgbHex.hex;
        return rgbHex;
      }
      static hsv2hex(hsv) {
        return hsv2rgb(hsv).hex;
      }
      static rgb2hex(rgb) {
        return hsv2rgb(rgb2hsv(rgb)).hex;
      }
      static hex2hsv(hex) {
        return rgb2hsv(ColorPicker.hex2rgb(hex));
      }
      static hex2rgb(hex) {
        return { r: parseInt(hex.substr(1, 2), 16), g: parseInt(hex.substr(3, 2), 16), b: parseInt(hex.substr(5, 2), 16) };
      }
      static positionIndicators(slideIndicator, pickerIndicator, mouseSlide, mousePicker) {
        if (mouseSlide) {
          pickerIndicator.style.left = "auto";
          pickerIndicator.style.right = "0px";
          pickerIndicator.style.top = "0px";
          slideIndicator.style.top = mouseSlide.y - slideIndicator.offsetHeight / 2 + "px";
        }
        if (mousePicker) {
          pickerIndicator.style.top = mousePicker.y - pickerIndicator.offsetHeight / 2 + "px";
          pickerIndicator.style.left = mousePicker.x - pickerIndicator.offsetWidth / 2 + "px";
        }
      }
      static fixIndicators(slideIndicator, pickerIndicator) {
        pickerIndicator.style.pointerEvents = "none";
        slideIndicator.style.pointerEvents = "none";
      }
    }

    function addEventListener(element, event, listener) {
      if (element.attachEvent) {
        element.attachEvent("on" + event, listener);
      } else if (element.addEventListener) {
        element.addEventListener(event, listener, false);
      }
    }

    function enableDragging(ctx, element, listener) {
      let mousedown = false;
      addEventListener(element, "mousedown", function (evt) {
        mousedown = true;
      });
      addEventListener(element, "mouseup", function (evt) {
        mousedown = false;
      });
      addEventListener(element, "mouseout", function (evt) {
        mousedown = false;
      });
      addEventListener(element, "mousemove", function (evt) {
        if (mousedown) {
          listener(evt);
        }
      });
    }

    ColorPicker.rgb2hsv = rgb2hsv;
    function setColor(ctx, hsv, rgb, hex) {
      ctx.h = hsv.h % 360;
      ctx.s = hsv.s;
      ctx.v = hsv.v;
      let c = hsv2rgb(ctx);
      let mouseSlide = {
        y: (ctx.h * ctx.slideElement.offsetHeight) / 360,
        x: 0,
      };

      let pickerHeight = ctx.pickerElement.offsetHeight;
      let mousePicker = {
        x: ctx.s * ctx.pickerElement.offsetWidth,
        y: pickerHeight - ctx.v * pickerHeight,
      };
      ctx.pickerElement.style.backgroundColor = hsv2rgb({ h: ctx.h, s: 1, v: 1 }).hex;
      ctx.callback && ctx.callback(hex || c.hex, { h: ctx.h, s: ctx.s, v: ctx.v }, rgb || { r: c.r, g: c.g, b: c.b }, mousePicker, mouseSlide);
      return ctx;
    }
    window.ColorPicker = ColorPicker;
  })(window, window.document);

  /* new DialogBox */

  class DialogBox {
    constructor({
      titleText = "Error",
      messageText = "Something unexpected has gone wrong. If the problem persists, contact your administrator",
      trueButtonText = "OK",
      falseButtonText = null,
      neutralButtonText = null,
    } = {}) {
      this.titleText = titleText;
      this.messageText = messageText;
      this.trueButtonText = trueButtonText;
      this.falseButtonText = falseButtonText;
      this.neutralButtonText = neutralButtonText;

      this.hasFalse = falseButtonText !== null;
      this.hasNeutral = neutralButtonText !== null;

      this.dialog = undefined;
      this.trueButton = undefined;
      this.falseButton = undefined;
      this.neutralButton = undefined;

      this.parent = document.body;

      this._createDialog(this);
      this._appendDialog();
    }

    _createDialog(context) {
      this.dialog = document.createElement("div");
      this.dialog.classList.add("dialog-box");

      this.dialog.style.opacity = 0;

      const title = document.createElement("div");
      title.textContent = this.titleText;
      title.classList.add("dialog-box-title");
      this.dialog.appendChild(title);

      const question = document.createElement("div");
      question.innerHTML = this.messageText;
      question.classList.add("dialog-box-message");
      this.dialog.appendChild(question);

      const buttonContainer = document.createElement("div");
      buttonContainer.classList.add("dialog-box-button-container");
      this.dialog.appendChild(buttonContainer);

      this.trueButton = document.createElement("a");
      this.trueButton.classList.add("dialog-box-button", "dialog-box-button--true");
      this.trueButton.textContent = this.trueButtonText;
      this.trueButton.addEventListener("click", function () {
        context._destroy();
      });
      buttonContainer.appendChild(this.trueButton);

      if (this.hasFalse) {
        this.falseButton = document.createElement("a");
        this.falseButton.classList.add("dialog-box-button", "dialog-box-button--false");
        this.falseButton.textContent = this.falseButtonText;
        this.falseButton.addEventListener("click", function () {
          context._destroy();
        });
        buttonContainer.appendChild(this.falseButton);
      }

      if (this.hasNeutral) {
        this.neutralButton = document.createElement("a");
        this.neutralButton.classList.add("dialog-box-button", "dialog-box-button--neutral");
        this.neutralButton.textContent = this.neutralButtonText;
        this.neutralButton.addEventListener("click", function () {
          context._destroy();
        });
        buttonContainer.appendChild(this.neutralButton);
      }
    }

    _appendDialog() {
      const diag = this.dialog;
      if (this.dialog) {
        this.parent.appendChild(diag);
        setTimeout(function () {
          diag.style.opacity = 1;
        }, 0);
      }
    }

    _destroy() {
      if (this.dialog) {
        this.parent.removeChild(this.dialog);
        delete this;
      }
    }

    respond() {
      return new Promise((resolve, reject) => {
        const somethingWentWrongUponCreation = !this.dialog || !this.trueButton;

        if (somethingWentWrongUponCreation) {
          reject(new Error("Something went wrong upon modal creation"));
        }

        this.trueButton.addEventListener("click", () => {
          resolve(true);
        });

        if (this.hasFalse) {
          this.falseButton.addEventListener("click", () => {
            resolve(false);
          });
        }
      });
    }
  }

  /* Slider Movements init */

  let Slider = {};
  Slider.scope = {};
  Slider.createTemplateTagFirstArg = function (e) {
    return (e.raw = e);
  };
  Slider.createTemplateTagFirstArgWithRaw = function (e, f) {
    e.raw = f;
    return e;
  };

  !(function (e) {
    class f {
      constructor(a, c) {
        let b = void 0 === c ? {} : c;
        c = void 0 === b.size ? 10 : b.size;
        let d = void 0 === b.val ? 0 : b.val;
        let g = void 0 === b.precision ? 0 : b.precision;
        let h = void 0 === b.range ? 1 : b.range;
        let k = void 0 === b.getVal ? function () {} : b.getVal;
        let l = void 0 === b.drag ? !0 : b.drag;
        let m = void 0 === b.direction ? "horizontal" : b.direction;
        b = void 0 === b.tip ? !1 : b.tip;
        if (!a) {
          error("//-> \u5fc5\u987b\u6307\u5b9a\u5b9e\u4f8b\u5bf9\u8c61\u7684\u5bb9\u5668\uff01");
        }
        this.container = document.querySelector(a);
        this.size = c;
        this.val = d;
        this.precision = g;
        this.range = h;
        this.getVal = k;
        this.drag = l;
        this.direction = m;
        if (typeof b === "object") {
          this.tip = b || {
            trigger: "show",
            align: "top",
          };
        } else if ("boolean" !== typeof b) {
          error("//-> tip\u914d\u7f6e\u9519\u8bef");
        }
        this.initialize();
      }
      initialize() {
        if (
          0 > this.size ||
          0 > this.val ||
          100 < this.val ||
          0 > this.precision ||
          4 < this.precision ||
          ("horizontal" !== this.direction && "vertical" !== this.direction) ||
          !this.container ||
          ("boolean" !== typeof this.drag && "object" !== typeof this.drag)
        ) {
          return error("//-> \u53c2\u6570\u914d\u7f6e\u9519\u8bef\uff01");
        }
        this.rander();
        this.renderLine();
      }
      rander() {
        this.bgBar = document.createElement("div");
        this.bgLine = document.createElement("div");
        this.btnTip = document.createElement("div");
        let a = this.bgBar;
        let c = this.container;
        let b = this.bgLine;
        let d = this.btnTip;
        switch (this.direction) {
          case "horizontal":
            a.classList.add("ProgressBar");
            a.style.height = this.size + "px";
            a.style.width = "100%";
            a.style.borderRadius = this.size / 2 + "px";
            b.appendChild(d);
            break;
          case "vertical":
            a.classList.add("ProgressBar");
            a.style.width = this.size + "px";
            a.style.height = "100%";
            a.style.borderRadius = this.size / 2 + "px";
            d.classList.add("vertical");
            b.appendChild(d);
        }
        d.classList.add("btnl");
        d.style.width = this.size + "px";
        d.style.height = this.size + "px";
        b.classList.add("ProgressLine");
        b.style.borderRadius = this.size / 2 + "px";
        a.appendChild(b);
        c.appendChild(a);
        this.drag ? this.Dragdrop() : this.btnTip.classList.add("disable");
        (this.tip || typeof this.tip === "object") && this.openTip();
        this.onLoading();
      }
      Dragdrop() {
        let a = this;
        let c = this.bgBar;
        let b = function (d) {
          a.getPos(d);
        };
        c.addEventListener("mousedown", function (d) {
          document.addEventListener("mousemove", b);
          a.getPos(d);
        });
        document.addEventListener("mouseup", function (d) {
          document.removeEventListener("mousemove", b);
        });
        c.addEventListener("touchstart", function (d) {
          document.addEventListener("touchmove", b);
          a.getPos(d);
        });
        document.addEventListener("touchend", function (d) {
          document.removeEventListener("touchmove", b);
        });
      }
      getPos(a) {
        typeof a.touches === "undefined" && (a.preventDefault(), a.stopPropagation());
        a.touches && (a = a.touches[0]);
        this.oldVal = this.val;
        let b, c;
        switch (this.direction) {
          case "horizontal":
            a = a.clientX + this.size / 2;
            c = this.bgBar.clientWidth;
            b = this.getElementLeft(this.bgBar);
            this.val = ((a - b - this.size) / (c - this.size)) * 100;
            break;
          case "vertical":
            a = a.clientY + this.size / 2;
            c = this.bgBar.clientHeight;
            b = this.getElementTop(this.bgBar);
            this.val = 100 - ((a - b - this.size) / (c - this.size)) * 100;
        }
        this.val = Math.max(0, this.val);
        this.val = Math.min(100, this.val);
        this.renderLine();
        this.eventVal();
      }
      getElementLeft(a) {
        let c = a.offsetLeft;
        for (a = a.offsetParent; null !== a; a) {
          c += a.offsetLeft;
          a = a.offsetParent;
        }
        return c;
      }
      getElementTop(a) {
        let c = a.offsetTop;
        for (a = a.offsetParent; null !== a; a) {
          c += a.offsetTop;
          a = a.offsetParent;
        }
        return c;
      }
      renderLine() {
        switch (this.direction) {
          case "horizontal":
            this.bgLine.style.width = ((this.bgBar.clientWidth - this.size) * this.val) / 100 + this.size + "px";
            break;
          case "vertical":
            this.bgLine.style.height = ((this.bgBar.clientHeight - this.size) * this.val) / 100 + this.size + "px";
        }
      }
      eventVal() {
        this.val = Number(this.val.toFixed(this.precision));
        this.oldVal !== this.val &&
          (this.getVal && this.getVal(this), this.tip || typeof this.tip === "object") &&
          (this.tipBox.innerText = String(((this.val / 100) * this.range).toFixed(this.precision + 2)));
      }
      updateVal(a) {
        0 > a ||
          100 < a ||
          ((this.val = Number(a)), this.renderLine(), (this.val = Number(a.toFixed(this.precision))), !this.tip && "object" !== typeof this.tip) ||
          (this.tipBox.innerText = String(((this.val / 100) * this.range).toFixed(this.precision + 2)));
      }
      openTip() {
        let a = this.btnTip;
        this.tipBox = document.createElement("span");
        this.tipBox.classList.add("progressVal");
        this.tipBox.innerText = String(((this.val / 100) * this.range).toFixed(this.precision + 2));
        a.appendChild(this.tipBox);
        this.tip.trigger && this.tipConfig();
      }
      tipConfig() {
        let a = this;
        switch (this.tip.trigger) {
          case "hover":
            this.tipBox.style.opacity = 0;
            this.bgBar.addEventListener("mouseenter", function () {
              return (a.tipBox.style.opacity = 1);
            });
            this.bgBar.addEventListener("mouseleave", function () {
              return (a.tipBox.style.opacity = 0);
            });
            this.bgBar.addEventListener("touchstart", function () {
              return (a.tipBox.style.opacity = 1);
            });
            this.bgBar.addEventListener("touchend", function () {
              return (a.tipBox.style.opacity = 0);
            });
            break;
          case "show":
            this.tipBox.style.opacity = 1;
        }
        switch (this.tip.align) {
          case "bottom":
            this.tipBox.classList.add("bottom");
            break;
          case "left":
            this.tipBox.classList.add("left");
            break;
          case "right":
            this.tipBox.classList.add("right");
        }
      }
      onLoading() {
        let a = (this.btnLoading = document.createElement("span"));
        let c = this.btnTip;
        a.classList.add("loading");
        c.appendChild(a);
        a.style.width = c.offsetWidth + "px";
        a.style.height = c.offsetHeight + "px";
      }
      onLoad(a, c) {
        c = void 0 === c ? function () {} : c;
        if ("boolean" !== typeof a) {
          error("//-> onload\u914d\u7f6e\u9519\u8bef");
        }
        a && (this.btnLoading.style.display = "block");
        c(this);
      }
    }
    e.Progress = f;
  })(window);

  function checkdraw(b, a, c) {
    b.value = ((a.val / 100) * a.range).toFixed(a.precision + 2);
    b.addEventListener("blur", function () {
      this.value <= a.range
        ? ((this.value = Number(this.value.match(c)).toFixed(a.precision + 2)), a.updateVal((100 * this.value) / a.range))
        : (this.value = ((a.val / 100) * a.range).toFixed(a.precision + 2));
    });
  }

  /* Font filtering & discriminating list */

  let fontSet = function (s) {
    return {
      that: Array.prototype.slice.call(document.querySelectorAll(s), 0),
      stopPropagation: function (e) {
        e = e || window.event;
        if (e.stopPropagation) {
          e.stopPropagation();
        } else {
          e.cancelBubble = true;
        }
      },
      hide: function () {
        fontSet(s).that.forEach(function (item) {
          item.style.cssText += "display:none";
        });
      },
      show: function () {
        fontSet(s).that.forEach(function (item) {
          item.style.cssText += "display:block";
        });
      },
      fdeleteList: function (fontData) {
        let ddRemove = function (dd) {
          let temp = dd.nextElementSibling;
          dd.remove();
          if (temp !== null && temp.nodeName === "DD") {
            ddRemove(temp);
          }
        };

        let selector = (function () {
          class selector {
            constructor(ch, en) {
              this.ch = ch;
              this.en = en;
            }
          }
          return selector;
        })();

        let close = fontSet("#fontSelect .close");
        close.that.forEach(function (item) {
          ddRemove(item.parentNode);
          let value = item.parentNode.children[1].value;
          let text = item.parentNode.children[0].innerHTML;
          fontData.push(new selector(text, value));
          if (fontSet("#fontSelect .close").that.length === 0) {
            fontSet("#fontSelect .selector").that[0].parentNode.style.cssText += "display:none;";
          }
        });

        return Boolean(close.that.length);
      },
      fsearchList: function (name) {
        let arr = [];
        fontSet("input[name=" + name + "]").that.forEach(item => {
          arr.push(item.value);
        });
        return arr;
      },
      fsearch: function (name, fontData) {
        let domId = fontSet(s).that[0];
        let html = String(
          `<div id="selector"><label>已选择:</label><div class="selector"></div></div><div class="selectId"><label>设置字体,请选择:</label><input type="text" placeholder="留空则初始化为微软雅黑" autocomplete="off"><dl style="display: none;"></dl><span class="fr_tooltip ps1">\ud83d\udd14<span class="fr_tooltiptext ps2"><strong>温馨提示:</strong><p>脚本预载了多种常用的、好看的中文字体,下拉菜单中所罗列的字体是您系统中已安装过的字体,没有安装过则不会显示。</p><p>在选择字体时,尽量减少字体种类。<b style="color:darkred">(请您注意)</b>字体是按您选择的先后顺序进行优先渲染的,所以多选不如之选一个您最想要的。</p></span></span></div>`
        );
        domId.innerHTML = html;

        fontSet("#fontSelect .selector").that[0].parentNode.style.cssText += "display:none;";

        function clickEvent() {
          fontSet("#fontSelect .selectId dl dd").that.forEach(function (item) {
            item.onclick = function (e) {
              let value = this.attributes.value.value.toString();
              if (value) {
                fontSet("#fontSelect .selector").that[0].innerHTML += String(
                  `<a href="javascript:void(0)" class="label"><span style="color:#fff;font-size:16px;font-family:${value}!important">${this.innerHTML}</span><input type="hidden" name="font-name" value="${value}"/><span class="close">×</span></a>`
                );
                fontSet(".selector").that[0].parentNode.style.cssText += "display:block;";
                for (let i = 0; i < fontData.length; i++) {
                  if (fontData[i].en === value) {
                    fontData.splice(i, 1);
                    i = fontData.length;
                  }
                }
                removeFontSelector();
              }
              fontSet(".selectId dl").hide();
              fontSet("#fontSelect .selectId input").that[0].value = "";
              e.stopPropagation();
            };
          });
        }
        let ddRemove = function (dd) {
          let temp = dd.nextElementSibling;
          dd.remove();
          if (temp !== null && temp.nodeName === "DD") {
            ddRemove(temp);
          }
        };

        fontSet("#fontSelect .selectId input").that[0].oninput = function () {
          let val = this.value;
          let dd = fontSet("#fontSelect .selectId dl dd").that[0];
          if (dd === "DD") {
            ddRemove(dd);
          }
          fontSet("#fontSelect .selectId dl").hide();
          if (fontData.length > 0) {
            fontSet("#fontSelect .selectId dl").show();
            let sear_1 = new RegExp(val);
            let judge_1 = false;
            fontSet("#fontSelect .selectId dl").that[0].innerHTML = "";
            fontData.forEach(function (item) {
              if (sear_1.test(item.name)) {
                judge_1 = true;
                fontSet("#fontSelect .selectId dl").that[0].innerHTML += String(
                  `<dd style="font-family:${item.en}!important" value="${item.en}">${item.ch}</dd>`
                );
              }
            });
            if (!judge_1) {
              fontSet("#fontSelect .selectId dl").that[0].innerHTML = "<dd>\u6682\u65E0\u6570\u636E</dd>";
            }
            clickEvent();
          }
        };

        fontSet("#fontSelect .selectId input").that[0].onclick = function (e) {
          let dd = fontSet("#fontSelect .selectId dl dd").that[0];
          if (dd === "DD") {
            ddRemove(dd);
          }
          if (fontData.length === 0) {
            this.innerHTML = "暂无数据";
          } else {
            fontSet("#fontSelect .selectId dl").show();
          }
          fontSet("#fontSelect .selectId dl").that[0].innerHTML = "";
          fontData.sort(function (a, b) {
            return a.en - b.en;
          });
          fontData.forEach(function (item) {
            fontSet("#fontSelect .selectId dl").that[0].innerHTML += String(
              `<dd style="font-family:${item.en}!important" value="${item.en}">${item.ch}</dd>`
            );
          });
          clickEvent();
          e.stopPropagation();
        };
        let selector = (function () {
          class selector {
            constructor(ch, en) {
              this.ch = ch;
              this.en = en;
            }
          }
          return selector;
        })();

        function removeFontSelector() {
          fontSet("#fontSelect .close").that.forEach(function (item) {
            item.onclick = function () {
              ddRemove(this.parentNode);
              let value = this.parentNode.children[1].value;
              let text = this.parentNode.children[0].innerHTML;
              fontData.push(new selector(text, value));
              if (fontSet("#fontSelect .close").that.length === 0) {
                fontSet("#fontSelect .selector").that[0].parentNode.style.cssText += "display:none;";
              }
            };
          });
        }

        document.onclick = function (e) {
          fontSet("#fontSelect .selectId dl").hide();
          fontSet("#fontSelect .selectId input").that[0].value = "";
        };
      },
    };
  };

  const fontCheck = new Set(
    [
      { ch: "微软雅黑", en: "Microsoft YaHei" },
      { ch: "微软正黑体", en: "Microsoft JhengHei" },
      { ch: "苹方-简", en: "PingFang SC" },
      { ch: "冬青黑体简", en: "Hiragino Sans GB" },
      { ch: "兰亭黑-简", en: "Lantinghei SC" },
      { ch: "儷黑 Pro", en: "LiHei Pro Medium" },
      { ch: "翩翩体-简", en: "Hanzipen SC" },
      { ch: "手札体-简", en: "Hannotate SC" },
      { ch: "娃娃体-简", en: "Wawati SC" },
      { ch: "魏碑-简", en: "Weibei SC" },
      { ch: "行楷-简", en: "Xingkai SC" },
      { ch: "雅痞-简", en: "Yapi SC" },
      { ch: "圆体-简", en: "Yuanti SC" },
      { ch: "华文黑体", en: "STHeiti" },
      { ch: "华文楷体", en: "STKaiti" },
      { ch: "华文细黑", en: "STXihei" },
      { ch: "华文彩云", en: "STCaiyun" },
      { ch: "华文琥珀", en: "STHupo" },
      { ch: "华文新魏", en: "STXinwei" },
      { ch: "华文隶书", en: "STLiti" },
      { ch: "华文行楷", en: "STXingkai" },
      { ch: "方正舒体", en: "FZShuTi" },
      { ch: "方正姚体", en: "FZYaoti" },
      { ch: "思源黑体", en: "Source Han Sans CN" },
      { ch: "思源宋体", en: "Source Han Serif SC" },
      { ch: "文泉驿微米黑", en: "WenQuanYi Micro Hei" },
      { ch: "汉仪旗黑 40S", en: "HYQihei 40S" },
      { ch: "汉仪旗黑 50S", en: "HYQihei 50S" },
      { ch: "汉仪旗黑 60S", en: "HYQihei 60S" },
      { ch: "幼圆", en: "YouYuan" },
      { ch: "楷体", en: "KaiTi" },
      { ch: "仿宋", en: "FangSong" },
      { ch: "隶书", en: "LiSu" },
    ].sort()
  );

  let isSupportFontFamily = function (f) {
    if (typeof f !== "string") {
      return false;
    }
    let h = "Arial";
    if (f.toLowerCase() === h.toLowerCase()) {
      return true;
    }
    let e = "a";
    let d = 100;
    let a = 100;
    let i = 100;
    let c = document.createElement("canvas");
    let b = c.getContext("2d");
    c.width = a;
    c.height = i;
    b.textAlign = "center";
    b.fillStyle = "black";
    b.textBaseline = "middle";
    let g = function (j) {
      b.clearRect(0, 0, a, i);
      b.font = d + "px " + j + ", " + h;
      b.fillText(e, a / 2, i / 2);
      let k = b.getImageData(0, 0, a, i).data;
      return [].slice.call(k).filter(function (l) {
        return l !== 0;
      });
    };
    return g(h).join("") !== g(f).join("");
  };

  /* define default value */

  const defValue = {
    fontSelect: `"Microsoft YaHei",Arial,Helvetica,sans-serif`,
    fontFace: true,
    fontStroke: 0.04,
    fontShadow: 1.0,
    shadowColor: "#d4d4d4",
    fontSmooth: true,
    fontCSS: `:not(.fa,.mi):not([class*="nav"]):not([class*="icon"]):not([class*="logo"]):not([class*="code"])`,
    fontEx: `pre *, code *,* input,* textarea,* kbd,* i,* em`,
  };
  const feedback = defCon.supportURL ? defCon.supportURL : "https://greasyfork.org/scripts/416688/feedback";
  const CONST = {};

  /* Start specific operation */

  !(async function () {
    // Get Promise Value
    const temp = await GMgetValue("_fonts_set_");
    let exSite = await GMgetValue("_Exclude_site_");

    if (!temp && !exSite) {
      sessionStorage.setItem("_temp_", 1);
      sessionStorage.setItem("_exSite_", 1);
    }

    if (Number(sessionStorage.getItem("_temp_")) && Number(sessionStorage.getItem("_exSite_"))) {
      setTimeout(async () => {
        let dialog = new DialogBox({
          trueButtonText: "好,去看看",
          falseButtonText: "不,算了吧",
          messageText: `<p><span style="font-size:32px;font-weight:900;color:red">您好</span>,这是您首次使用新版的字体渲染脚本,新版脚本可通过脚本菜单进行全局设置,可排除不需要渲染的域名等高级功能,告别旧版需要修改代码的大难题,具体功能敬请试用。</p><p>稍后,将为您打开新版脚本的介绍页面,您需要去看一下吗?</p>`,
          titleText: "温馨提示",
        });
        sessionStorage.clear();
        if (await dialog.respond()) {
          window.open(
            `https://openuserjs.org/scripts/t3xtf0rm4tgmail.com/%E5%AD%97%E4%BD%93%E6%B8%B2%E6%9F%93%EF%BC%88%E8%87%AA%E7%94%A8%E8%84%9A%E6%9C%AC%EF%BC%89`,
            "Guide"
          );
        }
        dialog = null;
      }, 100);
    }

    /* Exclude site */

    let obj = ["workstation-xi"].sort();
    let siteIndex;
    if (!exSite) {
      GMsetValue("_Exclude_site_", JSON.stringify(obj));
      exSite = obj;
    } else {
      exSite = JSON.parse(exSite);
      for (let i = 0; i < exSite.length; i++) {
        if (exSite[i] === location.hostname) {
          siteIndex = i;
          break;
        }
      }
    }

    /* Menus Insert */

    try {
      let Font_Set, Exclude_site, Feed_Back;
      Font_Set ? GMunregisterMenuCommand(Font_Set) : debug("No Font_Set");
      Exclude_site ? GMunregisterMenuCommand(Exclude_site) : debug("No Exclude_site");
      Feed_Back ? GMunregisterMenuCommand(Feed_Back) : debug("No Feed_Back");

      if (window.self === window.top) {
        if (siteIndex === undefined) {
          Font_Set = GMregisterMenuCommand("\ufff0\ud83c\udf13 字体渲染设置", () => {
            document.querySelector(`#${defCon.rndId}`).style = "visibility: visible;";
          });
          Exclude_site = GMregisterMenuCommand(`\ufff1\ud83d\udeab 排除渲染 ${location.hostname}`, async () => {
            exSite.push(location.hostname);
            GMsetValue("_Exclude_site_", JSON.stringify(exSite));
            let dialog = new DialogBox({
              trueButtonText: "确 定",
              messageText: "<p>" + location.hostname + " 已<b style='color:red'>禁止</b>字体渲染!</p><p>确定后页面将自动刷新!</p>",
              titleText: "禁止字体渲染",
            });
            if (await dialog.respond()) {
              dialog = null;
              location.reload();
            }
          });
        } else {
          Exclude_site = GMregisterMenuCommand(`\ufff1\ud83c\udf40 重新渲染 ${location.hostname}`, async () => {
            exSite.splice(siteIndex, 1);
            GMsetValue("_Exclude_site_", JSON.stringify(exSite));
            let dialog = new DialogBox({
              trueButtonText: "确 定",
              messageText: "<p>" + location.hostname + " 重新<b style='color:green'>开启</b>字体渲染!</p><p>确定后页面将自动刷新!</p>",
              titleText: "恢复字体渲染",
            });
            if (await dialog.respond()) {
              dialog = null;
              location.reload();
            }
          });
        }

        Feed_Back = GMregisterMenuCommand("\ufff9\ud83e\udde1 建议反馈", () => {
          window.open(feedback, "feedback");
        });
      }
    } catch (error) {
      error("%c[Error]%c\n%s", "font-weight:bold;color:red", "font-weight:bold;color:darkred", error);
    }

    /* Set Default Value & initialize */

    if (!temp) {
      saveDate("_fonts_set_", {
        fontSelect: defValue.fontSelect,
        fontFace: defValue.fontFace,
        fontStroke: defValue.fontStroke,
        fontShadow: defValue.fontShadow,
        shadowColor: defValue.shadowColor,
        fontSmooth: defValue.fontSmooth,
        fontCSS: defValue.fontCSS,
        fontEx: defValue.fontEx,
      });
      CONST.fontSelect = defValue.fontSelect;
      CONST.fontFace = defValue.fontFace;
      CONST.fontStroke = defValue.fontStroke;
      CONST.fontShadow = defValue.fontShadow;
      CONST.shadowColor = defValue.shadowColor;
      CONST.fontSmooth = defValue.fontSmooth;
      CONST.fontCSS = defValue.fontCSS;
      CONST.fontEx = defValue.fontEx;
    } else {
      const fontValue = JSON.parse(temp);
      CONST.fontSelect = fontValue.fontSelect;
      CONST.fontFace = fontValue.fontFace;
      CONST.fontStroke = fontValue.fontStroke;
      CONST.fontShadow = fontValue.fontShadow;
      CONST.shadowColor = fontValue.shadowColor;
      CONST.fontSmooth = fontValue.fontSmooth;
      CONST.fontCSS = fontValue.fontCSS;
      CONST.fontEx = fontValue.fontEx;
    }

    /* Operation of CSS value */

    let shadow = "";
    const shadow_r = parseFloat(CONST.fontShadow);
    const shadow_c = CONST.shadowColor;
    if (!isNaN(shadow_r) && shadow_r > 0 && shadow_r <= 8) {
      shadow = `text-shadow:-1px 1px ${shadow_r}px ${shadow_c},1px 1px ${shadow_r}px ${shadow_c},1px -1px ${shadow_r}px ${shadow_c},-1px -1px ${shadow_r}px ${shadow_c};`;
    }
    let stroke = "";
    const stroke_r = parseFloat(CONST.fontStroke);
    if (!isNaN(stroke_r) && stroke_r > 0 && stroke_r <= 1.0) {
      stroke = `-webkit-text-stroke:${stroke_r}px;text-stroke:${stroke_r}px;-webkit-text-fill-color:currentcolor;text-fill-color:currentcolor;`;
    }
    let smoothing = "";
    const smooth_i = Boolean(CONST.fontSmooth);
    if (smooth_i) {
      smoothing = `-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;`;
    }

    const fontfamily = `font-family:${CONST.fontSelect.toString()};`;
    let refont = CONST.fontSelect.toString().split(",")[0];
    refont = refont ? refont.replace(/"|'/g, "") : "";

    let fontface = "";
    if (CONST.fontFace) {
      fontface = refont
        ? `@font-face{font-family:"宋体";src:local("${refont}")}@font-face{font-family:"新宋体";src:local("${refont}")}@font-face{font-family:"黑体";src:local("${refont}")}@font-face{font-family:"Microsoft YaHei UI";src:local("${refont}")}@font-face{font-family:"Segoe UI";src:local("${refont}")}@font-face{font-family:"Microsoft YaHei";src:local("${refont}")}@font-face{font-family:"微软雅黑";src:local("${refont}")}@font-face{font-family:"PingFang SC";src:local("${refont}")}@font-face{font-family:Tahoma;src:local("${refont}")}@font-face{font-family:Arial;src:local("${refont}")}@font-face{font-family:Helvetica;src:local("${refont}")}`
        : ``;
    }
    const cssexlude = CONST.fontEx;
    const exclude = `${cssexlude}{text-stroke:0!important;-webkit-text-stroke:0!important;text-shadow:0 0 0 #fff!important}`;

    const cssfun = CONST.fontCSS;
    let tshadow = "";
    if (siteIndex === undefined) {
      tshadow = `${exclude}${cssfun}{${shadow}${stroke}${smoothing}${fontfamily}}${fontface}`;
    }
    const fontStyle = `.dialog-box{max-width:400px;color:#444;z-index:9999999;border:2px solid #efefef;-moz-border-radius:24px;border-radius:24px}.dialog-box *,.dialog-box *:hover{text-stroke:0!important;-webkit-text-stroke:0!important;text-shadow:0 0 0 #fff!important}.dialog-box-button--false{background:#d93223;color:#fff;border:1px solid #d93223;-moz-border-radius:6px;border-radius:6px;font-size:14px!important}.dialog-box-button--true{background:#038c5a;color:#fff;border:1px solid #038c5a;-moz-border-radius:6px;border-radius:6px;font-size:14px!important}.dialog-box-button--neutral{background:#777;color:#fff;border:1px solid #777;-moz-border-radius:6px;border-radius:6px;font-size:14px!important}.dialog-box{width:100%;display:block;position:fixed;right:-180px;top:500px;transform:translate(-50%,-50%);background:#fff;-webkit-box-shadow:0 0 10px 0 rgba(0,0,0,.3);-moz-box-shadow:0 0 10px 0 rgba(0,0,0,.3);box-shadow:0 0 10px 0 rgba(0,0,0,.3);border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;overflow:hidden;transition:opacity .3s}.dialog-box-message{color:#444;padding:10px;margin:10px;font-size:16px;font-weight:300}.dialog-box-message p{line-height:160%;margin:5px 0}.dialog-box-title{background:#efefef;margin-top:0;padding:12px;font-size:20px;font-weight:700;width:100%}.dialog-box-button{min-width:20%;letter-spacing:0;text-align:center;cursor:pointer;padding:10px;display:inline-block;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;margin:0 1%;font-size:12px;font-weight:300;transition:opacity .5s}.dialog-box-button:hover{color:#fff;opacity:.8}.dialog-box-button-container{text-align:right;padding:2.5%;background:#efefef;color:#ffffff;}#color-picker{display:none;min-height:205px;min-width:250px;z-index:999999;margin-top:40px;position:fixed}.picker-wrapper,.slide-wrapper{position:relative;float:left}.picker-indicator,.slide-indicator{position:absolute;left:0;top:0;pointer-events:none}.picker,.slide{cursor:crosshair;float:left}.cp-default{background-color:#d1f2fb;padding:10px;box-shadow:0 0 10px #000;border-radius:6px;float:left}.cp-default .picker{width:200px;height:200px;border:2px solid #222}.cp-default .slide{width:30px;height:200px}.cp-default .slide-wrapper{margin-left:10px}.cp-default .picker-indicator{width:5px;height:5px;border:2px solid #00008b;-moz-border-radius:4px;-o-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;opacity:.5;background-color:#fff}.cp-default .slide-indicator{width:100%;height:10px;left:-4px;opacity:.6;border:4px solid #add8e6;-moz-border-radius:4px;-o-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#fff}body #fr-container{background:#f0f6ff;border-radius:6px;-moz-border-radius:6px;position:fixed;top:10px;right:20px}#fr-container *{text-stroke:0!important;-webkit-text-stroke:0!important;text-shadow:0 0 0 #fff!important}#fr-container{width:340px;z-index:9999999;padding:3px 8px;text-align:left;background-color:#fff;color:#333;font-size:16px;font-weight:900;-webkit-transition:all .1s ease-in;transition:all .1s ease-in;}#fr-container strong{display:block;margin-bottom:10px}#fr-container p{display:block;margin:0 0 10px 0;line-height:140%}#fr-container ul li{list-style:none;margin:3px 0;-webkit-box-sizing:content-box;box-sizing:content-box;border:none;float:none;cursor:default}#fr-container fieldset{border:2px groove #67a5df;-moz-border-radius:10px;border-radius:10px;padding:4px 9px 6px 9px;margin:2px;display:block;width:auto;height:auto;min-height:500px}#fr-container legend{line-height:20px;padding:0 8px;margin-bottom:0;font-size:16px;font-weight:700;font-family:"Microsoft YaHei",sans-serif;-webkit-box-sizing:content-box;box-sizing:content-box;width:auto!important;min-width:185px!important}#fr-container fieldset>ul{padding:0;margin:0}#fr-container .setting-title{color:#8b0000}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}.setting-title .Rotation{bottom:auto;top:auto;left:auto;right:auto;-webkit-transform:rotate(360deg);animation:rotation 5s linear infinite;-moz-animation:rotation 5s linear infinite;-webkit-animation:rotation 5s linear infinite;-o-animation:rotation 5s linear infinite}#fontSelect{padding:2px 10px;min-height:80px}#fontFace,#fontSmooth{padding:2px 10px;height:40px;width:calc(100% -10px);min-width:calc(100% -10px)}#shadowColor{padding:2px 10px;min-height:45px;margin:4px width: calc(100% - 10px)}#fontShadow{padding:2px 10px;height:70px}#fontStroke{padding:2px 10px;height:70px}#submitData{padding:2px 10px;height:40px}#submitData button{background-color:#67a5df;color:#fff;padding:5px;font-size:14px;font-weight:400;border:2px solid #6ba7e0;-moz-border-radius:6px;border-radius:6px;width:50px}#submitData .cancel,#submitData .reset{float:left;margin-right:10px}#submitData .fr-submit{float:right}#fontCSS,#fontEx{padding:2px 10px;min-height:110px}#fontCSS textarea,#fontEx textarea{width:100%;max-width:calc(100% - 15px)!important;height:60px;resize:none;border:2px solid #67a5df;-moz-border-radius:6px;border-radius:6px;-webkit-box-sizing:content-box;box-sizing:content-box;padding:5px;font-family:"Fira Code",Monaco,consolas,sans-serif;font-size:14px;font-weight:500;color:#0b5b9c;scrollbar-color:rgba(0,0,0,.6) rgba(0,0,0,.25);scrollbar-width:thin;scrollbar-arrow-color:#fff;scrollbar-face-color:#4c4c4c;scrollbar-highlight-color:#4c4c4c;scrollbar-shadow-color:#4c4c4c;scrollbar-track-color:#bfbfbf;scrollbar-3dlight-color:#4c4c4c;scrollbar-darkshadow-color:#4c4c4c;scrollbar-base-color:#4c4c4c}#fontCSS textarea::-webkit-scrollbar,#fontEx textarea::-webkit-scrollbar{width:5px;height:5px}#fontCSS textarea::-webkit-scrollbar-track,#fontEx textarea::-webkit-scrollbar-track{border-radius:5px;background-color:rgba(0,0,0,.25)}#fontCSS textarea::-webkit-scrollbar-thumb,#fontEx textarea::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(0,0,0,.6)}.fr_tooltip{position:relative}.fr_tooltip .fr_tooltiptext{visibility:hidden;z-index:9999;width:220px;max-width:220px;background-color:#54a2ec;border:2px solid #b8c4ce;font-weight:400;color:#fff;border-radius:6px;-moz-border-radius:6px;padding:10px;position:absolute;font-size:14px;opacity:.9;-moz-opacity:.9;display:none;-webkit-box-sizing:content-box;box-sizing:content-box}.fr_tooltip:hover .fr_tooltiptext{visibility:visible;display:block}.ps1{top:-32px;left:250px}.ps2{top:-20px;left:-250px}.ps4{top:25px}#fontSelect .selector a{font-weight:400;color:#111;text-decoration:none}#fontSelect .label{padding:2px 0;background:#67a5df;border-radius:2px;-moz-border-radius:2px;color:#fff;display:block;line-height:20px;height:24px;margin:2px 5px 2px 0;float:left;-webkit-box-sizing:content-box;box-sizing:content-box;font-weight:400}#fontSelect .label span{padding:5px}#fontSelect .close{padding:1px 2px 5px 2px!important;color:#fff;-webkit-box-sizing:content-box;box-sizing:content-box}#fontSelect .close:hover{background-color:#366694;border-radius:2px;-moz-border-radius:2px;color:tomato}#fontSelect .selectId{width:calc(100% - 42px)}#fontSelect .selectId label{display:block;margin:5px 0}#fontSelect .selectId input{height:36px!important;padding:1px 25px!important;text-indent:0;font-size:16px;width:100%;max-width:calc(100% - 10px);outline-color:#67a5df;border:2px solid #67a5df;border-radius:6px;-moz-border-radius:6px;-webkit-box-sizing:content-box;box-sizing:content-box}#fontSelect .selectId dl{position:fixed;z-index:1000;width:100%;max-width:180px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#fff;border:2px solid #67a5df;border-radius:4px;-moz-border-radius:4px;margin:8px 0 0 0;padding:4px 25px;max-height:200px;font-size:18px;overflow-x:hidden;white-space:nowrap}#fontSelect .selectId dl dd{margin:0;padding:5px;font-weight:400}#fontSelect .selectId dl dd:hover{background-color:#67a5df;color:#fff}#selector{width:100%;max-width:100%}#fontSelect .selector{width:100%;max-width:calc(100% - 15px);overflow-y:auto;max-height:60px;border:2px solid #67a5df;border-radius:6px;-moz-border-radius:6px;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box}.checkbox{display:none!important}.checkbox+label{background-color:#fff;padding:11px 9px;border-radius:7px;display:inline-block;position:relative;background:#f7836d;width:58px;height:10px;box-shadow:inset 0 0 20px rgba(0,0,0,.1),0 0 10px rgba(245,146,146,.4);-webkit-box-sizing:content-box;box-sizing:content-box;word-wrap:normal!important}.checkbox+label:before{content:' ';position:absolute;background:#fff;top:0;z-index:999;left:0;width:24px;color:#fff;height:32px;border-radius:7px;-moz-border-radius:7px;box-shadow:0 0 1px rgba(0,0,0,.6);}.checkbox+label:after{content:'OFF';position:absolute;top:0;left:28px;font-size:1em;color:#fff;font-weight:700;padding:5px;border-radius:100px;-moz-border-radius:100px;-webkit-box-sizing:content-box;box-sizing:content-box}.checkbox:checked+label{-webkit-box-sizing:content-box;box-sizing:content-box;background:#67a5df;box-shadow:inset 0 0 20px rgba(0,0,0,.1),0 0 10px rgba(146,196,245,.4)}.checkbox:checked+label:after{content:'ON';left:10px;-webkit-box-sizing:content-box;box-sizing:content-box}.checkbox:checked+label:before{content:' ';position:absolute;z-index:999;left:52px;-webkit-box-sizing:content-box;box-sizing:content-box}#f-face label,#f-face+label:after,#f-face+label:before,#smooth label,#smooth+label:after,#smooth+label:before{-webkit-transition:all .1s ease-in;transition:all .1s ease-in;-webkit-box-sizing:content-box;box-sizing:content-box}#color-picker-show{float:left;display:block;margin-top:-6px}.cpicker{width:32px;height:32px;cursor:pointer;position:relative;border:2px solid #181a25;-moz-border-radius:4px;border-radius:4px;float:left;display:inline-block}.cpicker #color{width:125px;height:32px;text-indent:0;font-size:18px;-webkit-box-sizing:content-box;box-sizing:content-box;font-family:Impact,'Courier New',sans-serif!important;font-weight:400;border:#67a5df 2px solid;-moz-border-radius:4px;border-radius:4px;display:inline-block;padding:0 5px;margin-top:-2px;text-align:center}#fontShadow #shadowSize,#fontStroke #strokeSize{color:#111;width:56px;text-indent:0;margin-bottom:2px;float:right;height:32px;font-size:17px;font-family:Impact,'Courier New',sans-serif!important;border:#67a5df 2px solid;-moz-border-radius:4px;border-radius:4px;margin-right:2px;text-align:center;-webkit-box-sizing:content-box;box-sizing:content-box;padding:0}.progress{margin:2px;width:calc(100% - 10px)}.ProgressBar{background:#f0f0f0;margin:2px;width:250px;box-sizing:border-box;display:flex;align-items:flex-end;box-shadow:0 0 1px 1px rgba(0,0,0,.1) inset}.ProgressLine{width:100%;height:100%;position:relative;border-radius:15px;background:#67a5df}.ProgressLine .btnl{position:absolute;height:100%;right:0;border-radius:50%;font-size:8px;background:#67a5df;border:6px solid #fff;top:50%;transform:translate(6px,-50%);box-sizing:content-box!important;box-shadow:0 0 0 1px rgba(0,0,0,.2);display:flex;justify-content:center;align-items:center}.ProgressLine .btnl .disable{background:#ddd;border-color:#fafafa}.ProgressLine .btnl .loading{display:none;position:absolute;content:'';top:50%;left:50%;border-radius:50%;overflow:hidden;transform:translate(-50%,-50%);background:url(../images/loading1.gif);background-position:center center;background-size:130%;opacity:.5}@keyframes rate{0%{transform:translate(-50%,-50%) rotate(0)}100%{transform:translate(-50%,-50%) rotate(360deg)}}.vertical{top:0!important;left:50%!important;transform:translate(-50%,-6px)!important}.ProgressBar .progressVal{position:absolute;right:0;background:rgba(0,0,0,.4);text-align:center;width:45px;box-sizing:border-box;padding:0 4px;font-size:10px;color:#fff;height:20px;line-height:20px;border-radius:4px;top:-35px;left:50%;transform:translateX(-50%);transition:.5s linear}.ProgressBar .progressVal.bottom{top:auto;bottom:-35px}.ProgressBar .progressVal::after{position:absolute;content:'';border-width:5px 5px 0;border-style:solid;border-color:rgba(0,0,0,.4) transparent transparent;bottom:-5px;left:50%;transform:translateX(-50%)}.ProgressBar .progressVal.bottom::after{bottom:auto;top:-5px;border-width:0 5px 5px;border-style:solid;border-color:transparent transparent rgba(0,0,0,.4)}.ProgressBar .progressVal.left{top:auto;left:-40px}.ProgressBar .progressVal.left::after{top:50%;transform:translateY(-50%);left:auto;right:-5px;bottom:auto;border-width:5px 0 5px 5px;border-style:solid;border-color:transparent transparent transparent rgba(0,0,0,.4)}.ProgressBar .progressVal.right{top:auto;right:-85px;left:auto}.ProgressBar .progressVal.right::after{top:50%;transform:translateY(-50%);right:auto;left:-5px;bottom:auto;border-width:5px 5px 5px 0;border-style:solid;border-color:transparent rgba(0,0,0,.4) transparent transparent}`;
    const tHTML = String(`
    <div id="fr-container">
      <fieldset id="fr-autopager-field" style="display:block">
        <legend class="setting-title">
          <span style="display:inline-block">${defCon.scriptName}</span>
          <span style="display:inline-block;position:fixed;" onclick="window.open('https://openuserjs.org/scripts/t3xtf0rm4tgmail.com/%E5%AD%97%E4%BD%93%E6%B8%B2%E6%9F%93%EF%BC%88%E8%87%AA%E7%94%A8%E8%84%9A%E6%9C%AC%EF%BC%89','Guide')">
            <img class="Rotation" title="帮助文件" height="24" width="24" src="https://img.icons8.com/fluent/100/000000/help.png"/>
          <span>
        </legend>
        <ul class="setting-main">
          <li id="fontSelect">
            <div class="font-list"></div>
          </li>
          <li id="fontSmooth">
            <div style="float:left">字体平滑(默认:开)</div>
            <div style="float:right;margin:-5px 1px 0 0"><input type="checkbox" id="smooth" class="checkbox" ${CONST.fontSmooth ? "checked" : ""} />
            <label for="smooth"></label>
            </div>
          </li>
          <li id="fontFace">
            <div style="float:left">字体重写(默认:开)</div>
            <div style="float:right;margin:-5px 1px 0 0"><input type="checkbox" id="f-face" class="checkbox" ${CONST.fontFace ? "checked" : ""} />
            <label for="f-face"></label>
            </div>
          </li>
          <li id="fontStroke">
            <div style="margin-bottom:2px;min-width:calc(100% - 10px);float:left">字体描边尺寸<input id="strokeSize" /></div>
            <div id="stroke" class="progress"></div>
          </li>
          <li id="fontShadow">
            <div style="margin-bottom:2px;min-width:calc(100% - 10px);float:left">字体阴影尺寸<input id="shadowSize" /></div>
            <div id="shadow" class="progress"></div>
          </li>
          <li id="shadowColor">
            <div style="float:left;margin-right:10px">阴影颜色<span class="fr_tooltip">\ud83d\udd14<span class="fr_tooltiptext ps4"><p>阴影颜色可通过点击色块激活拾色器进行选择,也可自定义进行填写,填写格式如下:</p><p>HEX: #dbdbdb</p><p>RGB: rgb(133,133,133)</p><p>RGBA: rbga(236,236,236,0.8)</p><p>自身颜色: currentcolor</p><p><b style="color:darkred">注意:</b>格式错误,输入框变红</p></span></span></div>
            <div class="cpicker" id="color-picker-show"><input id="color" style="margin-left:40px"/></div>
            <div id="color-picker" class="cp-default">
                <div class="picker-wrapper">
                    <div id="picker" class="picker"></div>
                    <div id="picker-indicator" class="picker-indicator"></div>
                </div>
                <div class="slide-wrapper">
                    <div id="slide" class="slide"></div>
                    <div id="slide-indicator" class="slide-indicator"></div>
                </div>
            </div>
          </li>
          <li id="fontCSS">
            <div style="margin-bottom: 6px">需要渲染的元素:<span class="fr_tooltip">\ud83d\udd14<span class="fr_tooltiptext ps4">请将要渲染的元素用逗号分隔,默认为渲染全部元素,排除指定样式。(该选项需要CSS知识,请谨慎填写,样式若失效请重置)</span></span></div>
            <textarea id="cssfun">${CONST.fontCSS ? CONST.fontCSS : ""}</textarea>
          </li>
          <li id="fontEx">
            <div style="margin-bottom: 6px">排除渲染的元素:<span class="fr_tooltip">\ud83d\udd14<span class="fr_tooltiptext ps4">请将排除渲染的元素用逗号分隔,默认为元素标签。(该选项需要CSS知识,请谨慎填写,样式若失效请重置)</span></span></div>
            <textarea id="exclude">${CONST.fontEx ? CONST.fontEx : ""}</textarea>
          </li>
          <li id="submitData">
            <button class="reset">重置</button><button class="cancel">关闭</button><button class="fr-submit">保存</button>
          </li>
        </ul>
      </fieldset>
    </div>`);
    const tCSS = `@charset "UTF-8";` + tshadow + fontStyle;

    /* Insert HTML and CSS */

    function insertHTML() {
      if (document.body !== null && document.querySelector(`#${defCon.rndId}`) === null) {
        let div = document.createElement("div");
        div.id = defCon.rndId;
        div.style = "visibility:hidden;";
        div.innerHTML = tHTML;
        try {
          document.getElementsByTagName("body")[0].appendChild(div);
          return true;
        } catch (e) {
          console.log(e);
          return false;
        }
      }
    }

    function RAF() {
      RAFInterval(
        () => {
          if (!document.querySelector(`.${defCon.rndClass}`)) {
            addStyle(tCSS, `${defCon.rndClass}`, "head");
          }
          if (!document.querySelector(`#${defCon.rndId}`)) {
            insertHTML();
          }
        },
        200,
        true
      );
    }

    try {
      const callback = mutations => {
        mutations.forEach(mutation => {
          if (document.querySelector(`#${defCon.rndId}`) && document.querySelector(`.${defCon.rndClass}`)) {
            debug(`//-> Already Insert Button & CSS.`);
          } else {
            RAF();
          }
        });
      };
      const opts = { childList: true, subtree: true };
      let observer = new MutationObserver(callback);
      observer.observe(document, opts);

      /* Fonts selection */

      const fontReady = await document.fonts.ready;
      const fontAvailable = new Set();
      if (fontReady) {
        for (const font of fontCheck.values()) {
          if (isSupportFontFamily(font.en) || isSupportFontFamily(font.ch)) {
            fontAvailable.add(font);
          }
        }
      }
      const fontData = [...fontAvailable.values()];
      if (document.querySelector(`#${defCon.rndId}`)) {
        fontSet("#fontSelect .font-list").fsearch("fontSelect", fontData);
      }

      /* Fonts stroke */

      const strock = document.getElementById("strokeSize");
      const drawStrock = new Progress("#stroke", {
        val: CONST.fontStroke * 100,
        size: 10,
        precision: 1,
        range: 1,
        drag: true,
        direction: "horizontal",
        tip: {
          trigger: "hover",
          align: "right",
        },
        getVal: function (e) {
          strock.value = ((e.val / 100) * e.range).toFixed(e.precision + 2);
        },
      });
      drawStrock.onLoad(true, checkdraw(strock, drawStrock, /\d+(?:\.\d{1,3})?/));

      /* Fonts shadow */

      const shadows = document.getElementById("shadowSize");
      let drawShadow = new Progress("#shadow", {
        val: (CONST.fontShadow * 100) / 8,
        size: 10,
        precision: 0,
        range: 8,
        drag: true,
        direction: "horizontal",
        tip: {
          trigger: "hover",
          align: "right",
        },
        getVal: function (s) {
          shadows.value = ((s.val / 100) * s.range).toFixed(s.precision + 2);
        },
      });
      drawShadow.onLoad(false, checkdraw(shadows, drawShadow, /\d+(?:\.\d{1,2})?/));

      /* Fonts shadow color selection */

      const cpshow = document.querySelector("#color-picker-show");
      const cp = document.querySelector("#color-picker");
      const body = document.querySelector("body");
      const colorshow = document.querySelector("#color");
      let cpr = new ColorPicker(document.getElementById("slide"), document.getElementById("picker"), function (
        hex,
        hsv,
        rgb,
        mousePicker,
        mouseSlide,
        currentColor
      ) {
        currentColor = hex;
        ColorPicker.positionIndicators(
          document.getElementById("slide-indicator"),
          document.getElementById("picker-indicator"),
          mouseSlide,
          mousePicker
        );
        cpshow.style.backgroundColor = hex;
        colorshow.value = hex;
        colorshow.style.border = "2px solid #67a5df";
        colorshow.style.color = "black";
      });
      cpr.setHex(CONST.shadowColor);

      const colorReg =
        /^currentcolor$|^#([A-F0-9]{6}|[a-f0-9]{6}|[A-F0-9]{3}|[a-f0-9]{3})$|^rgba\(([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5]))),\s*([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5]))),\s*([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5]))),\s*((?!1.[1-9])[0-1](\.[0-9])?)\)$|^rgb\(([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5]))),\s*([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5]))),\s*([0-9]|([1-9][0-9])|(1[0-9][0-9])|(2([0-4][0-9]|5[0-5])))\)$/;
      colorshow.addEventListener("change", function () {
        if (colorReg.test(this.value.trim())) {
          cpr.setHex(this.value);
          colorshow.style.border = "2px solid #67a5df";
          colorshow.style.color = "black";
        } else {
          colorshow.style.border = "2px solid red";
          colorshow.style.color = "red";
        }
      });

      cpshow.addEventListener("click", function (e) {
        e.stopPropagation();
        cp.style = "display:block";
      });
      cp.addEventListener(
        "click",
        function (e) {
          e.stopPropagation();
        },
        false
      );
      body.addEventListener("click", function () {
        cp.style = "display:none";
      });

      /* Buttons control */

      document.querySelector("#submitData .reset").addEventListener("click", async () => {
        let dialog = new DialogBox({
          trueButtonText: "确 定",
          falseButtonText: "取 消",
          messageText: `<p>『重置』将初始化您所有的操作,脚本的所有参数将被还原为初始状态,一般是在您配置错误造成页面混乱后才会进行重置。</p><p style="color:red">注意,重置后记得保存数据!</p><p>请确认您是否要进行重置操作?</p>`,
          titleText: "参数重置确认",
        });

        if (await dialog.respond()) {
          fontSet().fdeleteList(fontData);
          strock.value = defValue.fontStroke.toFixed(3);
          drawStrock.updateVal((Number(defValue.fontStroke) * 100) / drawStrock.range);
          shadows.value = defValue.fontShadow.toFixed(2);
          drawShadow.updateVal((Number(defValue.fontShadow) * 100) / drawShadow.range);
          cpr.setHex(defValue.shadowColor);
          document.querySelector("#smooth").checked = defValue.fontSmooth;
          document.querySelector("#f-face").checked = defValue.fontFace;
          document.querySelector("#cssfun").value = defValue.fontCSS;
          document.querySelector("#exclude").value = defValue.fontEx;
        }
        dialog = null;
      });

      document.querySelector("#submitData .fr-submit").addEventListener("click", async () => {
        const fstrock = /[0-9]+(?:\.[0-9]{1,3})?/.test(strock.value) ? strock.value : defValue.fontStroke;
        const fshadow = /[0-9]+(?:\.[0-9]{1,3})?/.test(shadows.value) ? shadows.value : defValue.fontShadow;
        const pickedcolor = colorshow.value;
        const fscolor = colorReg.test(pickedcolor) ? pickedcolor : defValue.shadowColor;
        const fontlists = fontSet().fsearchList("font-name");
        const fontselect = fontlists.length > 0 ? String(fontlists.toString() + "," + defValue.fontSelect) : defValue.fontSelect;
        const smooth = document.querySelector("#smooth").checked;
        const fontface = document.querySelector("#f-face").checked;
        const fcss = document.querySelector("#cssfun").value;
        const cssfun = fcss ? fcss.toString() : defValue.fontCSS;
        const fex = document.querySelector("#exclude").value;
        const fontex = fex ? fex.toString() : defValue.fontEx;
        if (
          saveDate("_fonts_set_", {
            fontSelect: fontselect,
            fontFace: fontface,
            fontStroke: fstrock,
            fontShadow: fshadow,
            shadowColor: fscolor,
            fontSmooth: smooth,
            fontCSS: cssfun,
            fontEx: fontex,
          })
        ) {
          let dialog = new DialogBox({
            trueButtonText: "感谢使用",
            messageText: "<p>您的设置参数已保存!页面将会自动刷新!</p>",
            titleText: "操作完毕",
          });

          if (await dialog.respond()) {
            document.querySelector(`#${defCon.rndId}`).style = "visibility:hidden;";
            dialog = null;
            location.reload();
          }
        } else {
          let dialog = new DialogBox({
            trueButtonText: "反馈问题",
            messageText: "<p>保存过程中发生了错误!</p><p>请收集浏览器信息、脚本插件信息、以及脚本版本后,与作者联系反馈!</p>",
            titleText: "错误报告",
          });
          if (await dialog.respond()) {
            document.querySelector(`#${defCon.rndId}`).style = "visibility:hidden;";
            window.open(feedback, "feedback");
          }
          dialog = null;
        }
      });

      document.querySelector("#submitData .cancel").addEventListener("click", () => {
        document.querySelector(`#${defCon.rndId}`).style = "display:none";
      });
    } catch (e) {
      error("%c[Error]%c\n%s", "font-weight:bold;color:red", "font-weight:bold;color:darkred", e);
    }

    /* SYSTEM INFO */

    if (siteIndex === undefined) {
      let reFontFace = "";
      fontCheck.forEach(item => {
        if (item.en.toLowerCase() === refont.toLowerCase()) {
          reFontFace = item.en + "「" + item.ch + "」";
        }
      });
      console.info(
        `%c${defCon.scriptName}\n%c渲染字体:%s\n▞ 字体平滑:%s ▚ 字体重写:%s\n▞ 字体描边:%s ▚ 字体阴影:%s`,
        "line-height:160%;font-weight:bold;font-size:14px;color:red",
        "line-height:180%;font-size:12px;color:teal",
        reFontFace,
        CONST.fontSmooth ? "ON " : "OFF",
        CONST.fontFace ? "ON " : "OFF",
        Number(CONST.fontStroke) ? "ON " : "OFF",
        Number(CONST.fontShadow) ? "ON " : "OFF"
      );
    } else {
      console.info(
        `%c${defCon.scriptName}\n%c${location.hostname.toUpperCase()} 已在排除渲染列表内,若要重新渲染,请在脚本菜单中打开重新渲染。`,
        "line-height:160%;font-weight:bold;font-size:14px;color:red",
        "line-height:180%;font-size:12px;color:darkred"
      );
    }

    /* important Functions */

    function addStyle(css, className, addToTarget, isReload, initType) {
      RAFInterval(
        () => {
          let addTo = document.querySelector(addToTarget);
          if (typeof addToTarget === "undefined") {
            addTo = document.head || document.body || document.documentElement || document;
          }
          isReload = isReload || false;
          initType = initType || "text/css";
          if (typeof addToTarget === "undefined" || (typeof addToTarget !== "undefined" && document.querySelector(addToTarget) !== null)) {
            if (isReload === true) {
              safeRemove(`.${className}`);
            } else if (isReload === false && document.querySelector(`.${className}`) !== null) {
              return true;
            }
            const cssNode = document.createElement("style");
            if (className !== null) {
              cssNode.className = className;
            }
            cssNode.setAttribute("type", initType);
            cssNode.innerHTML = css;
            try {
              addTo.appendChild(cssNode);
            } catch (e) {
              error(`//-> ${e.name}`);
            }
            return true;
          }
          return false;
        },
        200,
        true
      );
    }

    function safeRemove(Css) {
      safeFunction(() => {
        const removeNodes = document.querySelectorAll(Css);
        for (let i = 0; i < removeNodes.length; i++) {
          removeNodes[i].remove();
        }
      });
    }

    function safeFunction(func) {
      try {
        func();
        return true;
      } catch (e) {
        error(`//-> ${e.name}`);
        return false;
      }
    }

    function RAFInterval(callback, period, runNow) {
      const needCount = (period / 1000) * 60;
      let times = 0;
      if (runNow === true) {
        const shouldFinish = callback();
        if (shouldFinish) {
          return;
        }
      }

      function step() {
        if (times < needCount) {
          times++;
          requestAnimationFrame(step);
        } else {
          const shouldFinish = callback() || false;
          if (!shouldFinish) {
            times = 0;
            requestAnimationFrame(step);
          } else {
            return;
          }
        }
      }
      requestAnimationFrame(step);
    }

    function saveDate(key, { ...Options }) {
      let obj = { ...Options };
      try {
        GMsetValue(key, JSON.stringify(obj));
        return true;
      } catch (e) {
        error(`//-> ${e.name}`);
        return false;
      }
    }
  })();
})();