// ==UserScript==
// @name 增强思否 (SegmentFault) 前端体验
// @namespace https://segmentfault.com/u/jamesfancy
// @version 1.0.11
// @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
/*!
* 粘贴带标题的 URL 时,处理成 Markdown 的 URL 格式
*/
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/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"));
}
// 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": "-1rem",
"margin-right": "-1rem",
padding: "0.5rem 1rem",
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
// @license MulanPSL-2.0
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();
});
})();