Greasy Fork

Greasy Fork is available in English.

增强思否 (SegmentFault) 前端体验

对思否社区的样式进行细节上的改善,支持 Chrome 77 及以上版本的浏览器。这是整合了问答和博客以及样式调整的脚本。

目前为 2022-08-18 提交的版本。查看 最新版本

// ==UserScript==
// @name         增强思否 (SegmentFault) 前端体验
// @namespace    https://segmentfault.com/u/jamesfancy
// @version      1.0.8
// @description  对思否社区的样式进行细节上的改善,支持 Chrome 77 及以上版本的浏览器。这是整合了问答和博客以及样式调整的脚本。
// @author       James Fan
// @license      MulanPSL-2.0
// @match        https://segmentfault.com/*
// @icon         https://cdn.segmentfault.com/r-e5cb5889/favicon.ico
// @grant        none
// ==/UserScript==

(() => {
  // src/util/functions.js
  function warn(...args) {
    var _a;
    ((_a = console.warn) != null ? _a : console.log)(...args);
  }

  // src/util/wait.js
  async function waitObject(getter, timeoutSeconds = 0, interval = 200) {
    const timeout = (timeoutSeconds || 0) * 1e3;
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      let errorCount = 0;
      const timer = setInterval(async () => {
        const result = await (async () => getter())().catch(() => (errorCount++, void 0));
        if (result != null ? result : false) {
          clearInterval(timer);
          resolve(result);
          return;
        }
        if (errorCount > 100) {
          clearInterval(timer);
          reject({ type: "too more error" });
        } else if (timeout && Date.now() - startTime > timeout) {
          clearInterval(timer);
          reject({ type: "timeout", seconds: timeoutSeconds });
        }
      }, interval);
    });
  }
  function warnWaitError(message) {
    return (err) => {
      warn(`[${err.type}]`, message);
      warn(err);
    };
  }

  // src/answer/paste-link.js
  async function injectToPasteLink() {
    var _a;
    if (!navigator.clipboard) {
      ((_a = console.warn) != null ? _a : console.log)("Clipboard API is not supported.");
    }
    const editor = await waitObject(() => {
      var _a2;
      return (_a2 = document.querySelector(".CodeMirror")) == null ? void 0 : _a2.CodeMirror;
    });
    editor.on("paste", async (cm, e) => {
      const md = getLinkMarkdown(e);
      if (md) {
        e.preventDefault();
        const doc = cm.getDoc();
        doc.replaceSelection(md);
      }
    });
    function getLinkMarkdown(e) {
      const data = e.clipboardData;
      const html = data.getData("text/html");
      const div = document.createElement("div");
      div.innerHTML = html;
      if (div.childElementCount !== 1) {
        return;
      }
      const a = div.children[0];
      if (a.tagName !== "A") {
        return;
      }
      return `[${a.innerText}](${a.href})`;
    }
  }

  // src/answer/reply-button.js
  async function moveReplyButtonUp() {
    const [replyArea, preview, buttons] = await waitObject(
      () => {
        const preview2 = document.getElementById("editor-preview-wrap");
        if (!preview2) {
          return;
        }
        const buttons2 = preview2.nextElementSibling;
        if (!buttons2) {
          return;
        }
        const replyArea2 = preview2.parentElement;
        return [replyArea2, preview2, buttons2];
      }
    );
    replyArea.insertBefore(buttons, preview);
    buttons.classList.remove("mt-3");
    buttons.classList.add("mb-3");
  }

  // src/answer/tags.js
  async function moveTagsUp() {
    const [context, info, tags] = await waitObject(() => {
      const context2 = document.querySelector(".introduction-wrap .card-body");
      if (!context2) {
        return;
      }
      const article = context2.querySelector("article");
      const info2 = article == null ? void 0 : article.previousElementSibling;
      if (!(info2 == null ? void 0 : info2.classList.contains("information"))) {
        return;
      }
      if (context2.children[1] !== info2) {
        return;
      }
      const tags2 = context2.querySelector("article").nextElementSibling;
      if (!(tags2 == null ? void 0 : tags2.querySelector("a.badge-tag"))) {
        return;
      }
      return [context2, info2, tags2];
    }, 5);
    context.insertBefore(tags, info.nextElementSibling);
  }

  // src/util/editor/index.js
  function getCodeMirror() {
    var _a;
    return (_a = document.querySelector(".CodeMirror")) == null ? void 0 : _a.CodeMirror;
  }

  // src/util/editor/answer.js
  async function waitAnswerEditorWrapper() {
    return await waitObject(() => document.querySelector(".sf-editor-wrap"));
  }

  // src/answer/add-tail.js
  function addTailToEditor(text) {
    const content = `

---

> ${text}
`;
    const editor = getCodeMirror();
    if (!editor) {
      return;
    }
    const doc = editor.getDoc();
    const pos = { line: editor.lineCount() };
    doc.replaceRange(content, pos);
  }
  function createIcon(...classList) {
    if (!(classList == null ? void 0 : classList.length)) {
      classList = ["fa-solid", "fa-file-signature"];
    }
    const icon = document.createElement("i");
    icon.classList.add(...classList);
    return icon;
  }
  function createImageIcon(url) {
    const img = document.createElement("img");
    img.src = url;
    img.width = "100%";
    img.style.objectFit = "cover";
    img.style.position = "center";
    return img;
  }
  function getIconCreator(icon) {
    switch (typeof icon) {
      case "string":
        if (icon.includes("/")) {
          return () => createImageIcon(icon);
        } else {
          return () => createIcon(icon.split(","));
        }
      case "function":
        return icon;
      default:
        if (Array.isArray(icon)) {
          return () => createIcon(...icon);
        }
        return createIcon;
    }
  }
  function createIconButton(icon, fn) {
    const button = document.createElement("button");
    button.type = "button";
    button.classList.add("p-0", "b-0", "toolbar");
    button.title = "\u6DFB\u52A0\u5341\u5468\u5E74\u300C\u95EE\u7B54\u300D\u6D3B\u52A8\u5C0F\u5C3E\u5DF4";
    Object.assign(button.style, {
      background: "none",
      color: "#e44d26"
    });
    button.appendChild(getIconCreator(icon)());
    button.addEventListener("click", fn);
    const div = document.createElement("div");
    div.classList.add("toolbar-item-wrap");
    div.appendChild(button);
    return div;
  }
  async function addAnswerTail(text, icon) {
    const editorWrap = await waitAnswerEditorWrapper();
    const toolbar = editorWrap.querySelector(".toolbar-wrap");
    const lastChild = toolbar.children[toolbar.children.length - 1];
    toolbar.insertBefore(
      (() => {
        const div = document.createElement("div");
        div.classList.add("toolbar-divider");
        return div;
      })(),
      lastChild
    );
    toolbar.insertBefore(createIconButton(icon, () => addTailToEditor(text)), lastChild);
  }

  // src/answer/index.js
  function answer_default() {
    moveTagsUp().catch(warnWaitError("wait tags elements failed"));
    moveReplyButtonUp().catch(warnWaitError("wait reply button failed"));
    injectToPasteLink().catch(warnWaitError("wait editor failed"));
    addAnswerTail("\u5DF2\u53C2\u4E0E [\u300C\u6781\u5BA2\u89C2\u70B9\u300D](https://segmentfault.com/a/1190000042331835) \uFF0C\u6B22\u8FCE\u6B63\u5728\u9605\u8BFB\u7684\u4F60\u4E5F\u52A0\u5165\u3002").catch(warnWaitError("wait answer editor failed"));
  }

  // src/styles/styles.json
  var styles_default = {
    ".fmt": {
      h6: {
        "font-weight": "bold",
        "&::before": {
          content: '"\u{1F4D1}"'
        }
      }
    },
    kbd: {
      "margin-left": "0.2rem",
      "margin-right": "0.2rem",
      background: "#e5f4ef",
      color: "#333333",
      border: "1px solid #00965e",
      "border-bottom": "2px solid #008050",
      "border-right": "2px solid #008050"
    },
    "#questionMain": {
      ".introduction-wrap": {
        "> .card-body": {
          "h1+div+div": {
            "margin-left": "-1.875rem",
            "margin-right": "-1.875rem",
            padding: "0.5rem 1.875rem",
            background: "rgba(0,150,94,.1)",
            "a.badge-tag": {
              background: "transparent"
            }
          }
        }
      }
    }
  };

  // src/styles/stringify.js
  function toStyleList(styles, selector) {
    const entries = Object.entries(styles);
    const attrEntries = entries.filter(([, value]) => typeof value !== "object");
    const currentStyle = attrEntries.length ? `${selector} { ${attrEntries.map(([key, value]) => `${key}: ${value}`).join("; ")} }` : null;
    const subEntries = entries.filter(([, value]) => typeof value === "object").flatMap(([key, value]) => toStyleList(value, mergeKey(selector, key)));
    if (currentStyle) {
      subEntries.unshift(currentStyle);
    }
    return subEntries;
  }
  function mergeKey(parent, key) {
    if (!parent) {
      return key;
    }
    if (key.startsWith("&")) {
      return `${parent}${key.substring(1)}`;
    }
    return `${parent} ${key}`;
  }
  function toStyleString(styles) {
    return toStyleList(styles).join("\n");
  }

  // src/styles/index.js
  function styles_default2() {
    const styleEl = document.createElement("style");
    styleEl.setAttribute("type", "text/css");
    styleEl.innerText = toStyleString(styles_default);
    document.head.appendChild(styleEl);
  }

  // src/customize-sifou.js
  var policies = [
    ["/q/", answer_default, "segmentfault.com/q/: improve answer"],
    [, styles_default2, "global: improve styles"]
  ].map(([rule, ...rest]) => {
    switch (typeof rule) {
      case "function":
        return [rule, ...rest];
      case "string":
        return [
          () => window.location.pathname.startsWith(rule),
          ...rest
        ];
      case "boolean":
        return [() => !!rule, ...rest];
      case "undefined":
        return [() => true, ...rest];
    }
  });
  policies.filter(([rule]) => rule()).forEach(([, fn, info]) => {
    var _a;
    ((_a = console.info) != null ? _a : console.log)("[SF-MONKEY]", info);
    return fn();
  });
})();
// @license      MulanPSL-2.0