// ==UserScript==
// @name V2Next
// @namespace http://tampermonkey.net/
// @version 8.0.6
// @author zyronon
// @description V2Next - 一个好用的V2EX脚本! 已适配移动端
// @license GPL License
// @icon https://v2next.netlify.app/favicon.ico
// @homepage https://github.com/zyronon/web-scripts
// @homepageURL https://github.com/zyronon/web-scripts
// @supportURL https://update.greasyfork.icu/scripts/458024/V2Next.user.js
// @match https://v2ex.com/
// @match https://v2ex.com/?tab=*
// @match https://v2ex.com/t/*
// @match https://v2ex.com/recent*
// @match https://v2ex.com/go/*
// @match https://v2ex.com/member/*
// @match https://v2ex.com/changes*
// @match https://*.v2ex.com/
// @match https://*.v2ex.com/?tab=*
// @match https://*.v2ex.com/t/*
// @match https://*.v2ex.com/recent*
// @match https://*.v2ex.com/go/*
// @match https://*.v2ex.com/member/*
// @match https://*.v2ex.com/changes*
// @require https://cdn.jsdelivr.net/npm/vue@3.4.14/dist/vue.global.prod.js
// @grant GM_addStyle
// @grant GM_notification
// @grant GM_openInTab
// @grant GM_registerMenuCommand
// @downloadURL none
// ==/UserScript==
(function (vue) {
'use strict';
var PageType = /* @__PURE__ */ ((PageType2) => {
PageType2["Home"] = "Home";
PageType2["Node"] = "Node";
PageType2["Post"] = "Post";
PageType2["Member"] = "Member";
PageType2["Changes"] = "Changes";
return PageType2;
})(PageType || {});
var CommentDisplayType = /* @__PURE__ */ ((CommentDisplayType2) => {
CommentDisplayType2[CommentDisplayType2["FloorInFloor"] = 0] = "FloorInFloor";
CommentDisplayType2[CommentDisplayType2["FloorInFloorNoCallUser"] = 4] = "FloorInFloorNoCallUser";
CommentDisplayType2[CommentDisplayType2["FloorInFloorNested"] = 5] = "FloorInFloorNested";
CommentDisplayType2[CommentDisplayType2["Like"] = 1] = "Like";
CommentDisplayType2[CommentDisplayType2["V2exOrigin"] = 2] = "V2exOrigin";
CommentDisplayType2[CommentDisplayType2["OnlyOp"] = 3] = "OnlyOp";
CommentDisplayType2[CommentDisplayType2["New"] = 6] = "New";
return CommentDisplayType2;
})(CommentDisplayType || {});
const MAX_REPLY_LIMIT = 400;
const _sfc_main$l = {
name: "Tooltip",
props: {
title: {
type: String,
default() {
return "";
}
},
disabled: {
type: Boolean,
default() {
return false;
}
}
},
data() {
return {
show: false
};
},
methods: {
showPop(e2) {
if (this.disabled)
return;
if (!this.title)
return;
e2.stopPropagation();
let rect = e2.target.getBoundingClientRect();
this.show = true;
vue.nextTick(() => {
var _a, _b;
let tip = (_b = (_a = this.$refs) == null ? void 0 : _a.tip) == null ? void 0 : _b.getBoundingClientRect();
if (!tip)
return;
if (rect.top < 50) {
this.$refs.tip.style.top = rect.top + rect.height + 10 + "px";
} else {
this.$refs.tip.style.top = rect.top - tip.height - 10 + "px";
}
let tipWidth = tip.width;
let rectWidth = rect.width;
this.$refs.tip.style.left = rect.left - (tipWidth - rectWidth) / 2 + "px";
});
}
},
render() {
let Vnode = this.$slots.default()[0];
return vue.createVNode(vue.Fragment, null, [this.show && this.title && vue.createVNode(vue.Teleport, {
"to": "body"
}, {
default: () => [vue.createVNode(vue.Transition, {
"name": "fade"
}, {
default: () => [vue.createVNode("div", {
"ref": "tip",
"className": "tip"
}, [this.title])]
})]
}), vue.createVNode(Vnode, {
"onClick": () => this.show = false,
"onmouseenter": (e2) => this.showPop(e2),
"onmouseleave": () => this.show = false
}, null)]);
}
};
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-ee672411"]]);
const _sfc_main$k = /* @__PURE__ */ vue.defineComponent({
__name: "BaseSwitch",
props: {
modelValue: { type: Boolean }
},
emits: ["update:modelValue"],
setup(__props, { emit: __emit }) {
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["switch", { active: _ctx.modelValue }]),
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", !_ctx.modelValue))
}, null, 2);
};
}
});
const BaseSwitch = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-e7c0fbef"]]);
var _GM_notification = /* @__PURE__ */ (() => typeof GM_notification != "undefined" ? GM_notification : void 0)();
var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)();
var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
const functions = {
//获取所有回复
getAllReply(repliesMap = []) {
return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
pre = pre.concat(i.replyList);
return pre;
}, []);
},
//查找子回复
findChildren(item, endList, all) {
var _a;
const fn = (child, endList2, parent) => {
child.level = parent.level + 1;
let rIndex = all.findIndex((v) => v.floor === child.floor);
if (rIndex > -1) {
all[rIndex].isUse = true;
}
parent.children.push(this.findChildren(child, endList2, all));
};
item.children = [];
let floorReplyList = [];
for (let i = 0; i < endList.length; i++) {
let currentItem = endList[i];
if (currentItem.isUse)
continue;
if (currentItem.replyFloor === item.floor) {
if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
currentItem.isUse = true;
floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
} else {
currentItem.isWrong = true;
}
}
}
floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
fn(currentItem, endList2, item);
});
let nextMeIndex = endList.findIndex((v) => {
var _a2;
return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
});
let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
for (let i = 0; i < findList.length; i++) {
let currentItem = findList[i];
if (currentItem.isUse)
continue;
if (currentItem.replyUsers.length === 1) {
if (currentItem.replyFloor !== -1) {
if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
continue;
}
}
let endList2 = endList.slice(i + 1);
if (currentItem.username === item.username) {
if (currentItem.replyUsers[0] === item.username) {
fn(currentItem, endList2, item);
}
break;
} else {
if (currentItem.replyUsers[0] === item.username) {
fn(currentItem, endList2, item);
}
}
} else {
if (currentItem.username === item.username)
break;
}
}
item.children = item.children.sort((a, b) => a.floor - b.floor);
return item;
},
//生成嵌套回复
createNestedList(allList = []) {
if (!allList.length)
return [];
let list = window.clone(allList);
let nestedList = [];
list.map((item, index) => {
let startList = list.slice(0, index);
let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
let endList = list.slice(index + 1);
if (index === 0) {
nestedList.push(this.findChildren(item, endList, list));
} else {
if (!item.isUse) {
let isOneLevelReply = false;
if (item.replyUsers.length) {
if (item.replyUsers.length > 1) {
isOneLevelReply = true;
} else {
isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
}
} else {
isOneLevelReply = true;
}
if (isOneLevelReply) {
item.level = 0;
nestedList.push(this.findChildren(item, endList, list));
}
}
}
});
return nestedList;
},
//生成嵌套冗余回复
createNestedRedundantList(allList = []) {
if (!allList.length)
return [];
let list = window.clone(allList);
let nestedList = [];
list.map((item, index) => {
let startList = list.slice(0, index);
let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
let endList = list.slice(index + 1);
if (index === 0) {
nestedList.push(this.findChildren(item, endList, list));
} else {
if (!item.isUse) {
let isOneLevelReply = false;
if (item.replyUsers.length) {
if (item.replyUsers.length > 1) {
isOneLevelReply = true;
} else {
isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
}
} else {
isOneLevelReply = true;
}
if (isOneLevelReply) {
item.level = 0;
nestedList.push(this.findChildren(item, endList, list));
}
} else {
let newItem = window.clone(item);
newItem.children = [];
newItem.level = 0;
newItem.isDup = true;
nestedList.push(newItem);
}
}
});
return nestedList;
},
//解析A标签
parseA(a) {
let href = a.href;
let id;
if (href.includes("/t/")) {
id = a.pathname.substring("/t/".length);
}
return { href, id, title: a.innerText };
},
//图片链接转Img标签
checkPhotoLink2Img(str) {
if (!str)
return;
try {
let imgWebs = [
/(((?!/g,
/(((?!/g
];
imgWebs.map((v, i) => {
let has = str.matchAll(v);
let res2 = [...has];
res2.map((r2) => {
let p = i === 0 ? r2[4] : r2[5];
if (p) {
let link = p.toLowerCase();
let src = p;
if (link.includes(".png") || link.includes(".jpg") || link.includes(".jpeg") || link.includes(".gif")) {
} else {
src = p + ".png";
}
str = str.replace(r2[0], ``);
}
});
});
} catch (e2) {
console.log("正则解析html里面的a标签的图片链接出错了");
}
return str;
},
//检测帖子回复长度
async checkPostReplies(id, needOpen = true) {
return new Promise(async (resolve) => {
let res = await functions.getPostDetailByApi(id);
if ((res == null ? void 0 : res.replies) > MAX_REPLY_LIMIT) {
if (needOpen) {
functions.openNewTab(`https://${location.origin}/t/${id}?p=1&script=1`);
}
return resolve(true);
}
resolve(false);
});
},
async sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
},
//打开新标签页
openNewTab(href, active = false) {
_GM_openInTab(href, { active });
},
async cbChecker(val, count = 0) {
if (window.cb) {
window.cb(val);
} else {
while (!window.cb && count < 30) {
await functions.sleep(500);
count++;
}
window.cb && window.cb(val);
}
},
//初始化脚本菜单
initMonkeyMenu() {
try {
_GM_registerMenuCommand("脚本设置", () => {
functions.cbChecker({ type: "openSetting" });
});
_GM_registerMenuCommand("仓库地址", () => {
functions.openNewTab(window.const.git);
});
_GM_registerMenuCommand("反馈 & 建议", functions.feedback);
} catch (e2) {
console.error("无法使用Tampermonkey");
}
},
clone(val) {
return JSON.parse(JSON.stringify(val));
},
feedback() {
functions.openNewTab(DefaultVal.issue);
},
//检测页面类型
checkPageType() {
let l = window.location;
if (l.pathname === "/") {
window.pageType = PageType.Home;
} else if (l.pathname === "/changes") {
window.pageType = PageType.Changes;
} else if (l.pathname === "/recent") {
window.pageType = PageType.Changes;
} else if (l.href.match(/.com\/?tab=/)) {
window.pageType = PageType.Home;
} else if (l.href.match(/.com\/go\//)) {
if (!l.href.includes("/links")) {
window.pageType = PageType.Node;
}
} else if (l.href.match(/.com\/member/)) {
window.pageType = PageType.Member;
} else {
let r2 = l.href.match(/.com\/t\/([\d]+)/);
if (r2 && !location.pathname.includes("review") && !location.pathname.includes("info")) {
window.pageType = PageType.Post;
window.pageData.id = r2[1];
if (l.search) {
let pr = l.href.match(/\?p=([\d]+)/);
if (pr)
window.pageData.pageNo = Number(pr[1]);
}
}
}
},
//通过api获取主题详情
getPostDetailByApi(id) {
return new Promise((resolve) => {
fetch(`${location.origin}/api/topics/show.json?id=${id}`).then(async (r2) => {
if (r2.status === 200) {
let res = await r2.json();
if (res) {
let d2 = res[0];
resolve(d2);
}
}
});
});
},
appendPostContent(res, el) {
let a = document.createElement("a");
a.href = res.href;
a.classList.add("post-content");
let div = document.createElement("div");
div.innerHTML = res.content_rendered;
a.append(div);
el.append(a);
const checkHeight2 = () => {
var _a;
if (div.clientHeight < 300) {
a.classList.add("show-all");
} else {
let showMore = document.createElement("div");
showMore.classList.add("show-more");
showMore.innerHTML = "显示更多/收起";
showMore.onclick = function(e2) {
e2.stopPropagation();
a.classList.toggle("show-all");
};
(_a = a.parentNode) == null ? void 0 : _a.append(showMore);
}
};
checkHeight2();
},
//从本地读取配置
initConfig() {
return new Promise((resolve) => {
let configStr = localStorage.getItem("v2ex-config");
if (configStr) {
let configObj = JSON.parse(configStr);
configObj = configObj[window.user.username ?? "default"];
if (configObj) {
window.config = Object.assign(window.config, configObj);
}
}
resolve(window.config);
});
}
};
const DefaultPost = {
allReplyUsers: [],
content_rendered: "",
createDate: "",
createDateAgo: "",
fr: "",
replyList: [],
nestedReplies: [],
nestedRedundReplies: [],
username: "",
url: "",
href: "",
member: {},
node: {
title: "",
url: ""
},
headerTemplate: "",
title: "",
id: "",
type: "post",
once: "",
replyCount: 0,
clickCount: 0,
thankCount: 0,
collectCount: 0,
lastReadFloor: 0,
isFavorite: false,
isIgnore: false,
isThanked: false,
isReport: false,
inList: false
};
const getDefaultPost = (val = {}) => {
return Object.assign(functions.clone(DefaultPost), val);
};
const DefaultUser = {
tagPrefix: "--用户标签--",
tags: {},
tagsId: "",
username: "",
avatar: "",
readPrefix: "--已读楼层--",
readNoteItemId: "",
readList: {},
imgurPrefix: "--imgur图片删除hash--",
imgurList: {},
imgurNoteId: ""
};
const DefaultConfig = {
showToolbar: true,
autoOpenDetail: true,
openTag: false,
//给用户打标签
clickPostItemOpenDetail: true,
closePostDetailBySpace: true,
//点击空白处关闭详情
contentAutoCollapse: true,
//正文超长自动折叠
viewType: "table",
commentDisplayType: CommentDisplayType.FloorInFloorNoCallUser,
newTabOpen: false,
//新标签打开
newTabOpenActive: false,
base64: true,
//base功能
sov2ex: false,
postWidth: "",
showTopReply: true,
topReplyLoveMinCount: 3,
topReplyCount: 3,
autoJumpLastReadFloor: false,
rememberLastReadFloor: false,
autoSignin: true,
customBgColor: "",
version: 1,
collectBrowserNotice: false,
fontSizeType: "normal"
};
const DefaultVal = {
pageType: void 0,
pageData: { pageNo: 1 },
targetUserName: "",
currentVersion: 1,
isNight: false,
cb: null,
stopMe: null,
postList: [],
git: "https://github.com/zyronon/web-scripts",
shortGit: "zyronon/web-scripts",
issue: "https://github.com/zyronon/web-scripts/issues",
pcLog: "https://greasyfork.org/zh-CN/scripts/458024/versions",
pcScript: "https://greasyfork.org/zh-CN/scripts/458024",
mobileScript: "https://greasyfork.org/zh-CN/scripts/485356",
homeUrl: "https://v2next.netlify.app/"
};
const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
const colonSeparated = value.split(":");
if (value.slice(0, 1) === "@") {
if (colonSeparated.length < 2 || colonSeparated.length > 3) {
return null;
}
provider = colonSeparated.shift().slice(1);
}
if (colonSeparated.length > 3 || !colonSeparated.length) {
return null;
}
if (colonSeparated.length > 1) {
const name2 = colonSeparated.pop();
const prefix = colonSeparated.pop();
const result = {
// Allow provider without '@': "provider:prefix:name"
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
prefix,
name: name2
};
return validate && !validateIconName(result) ? null : result;
}
const name = colonSeparated[0];
const dashSeparated = name.split("-");
if (dashSeparated.length > 1) {
const result = {
provider,
prefix: dashSeparated.shift(),
name: dashSeparated.join("-")
};
return validate && !validateIconName(result) ? null : result;
}
if (allowSimpleName && provider === "") {
const result = {
provider,
prefix: "",
name
};
return validate && !validateIconName(result, allowSimpleName) ? null : result;
}
return null;
};
const validateIconName = (icon, allowSimpleName) => {
if (!icon) {
return false;
}
return !!((icon.provider === "" || icon.provider.match(matchIconName)) && (allowSimpleName && icon.prefix === "" || icon.prefix.match(matchIconName)) && icon.name.match(matchIconName));
};
const defaultIconDimensions = Object.freeze(
{
left: 0,
top: 0,
width: 16,
height: 16
}
);
const defaultIconTransformations = Object.freeze({
rotate: 0,
vFlip: false,
hFlip: false
});
const defaultIconProps = Object.freeze({
...defaultIconDimensions,
...defaultIconTransformations
});
const defaultExtendedIconProps = Object.freeze({
...defaultIconProps,
body: "",
hidden: false
});
function mergeIconTransformations(obj1, obj2) {
const result = {};
if (!obj1.hFlip !== !obj2.hFlip) {
result.hFlip = true;
}
if (!obj1.vFlip !== !obj2.vFlip) {
result.vFlip = true;
}
const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
if (rotate) {
result.rotate = rotate;
}
return result;
}
function mergeIconData(parent, child) {
const result = mergeIconTransformations(parent, child);
for (const key in defaultExtendedIconProps) {
if (key in defaultIconTransformations) {
if (key in parent && !(key in result)) {
result[key] = defaultIconTransformations[key];
}
} else if (key in child) {
result[key] = child[key];
} else if (key in parent) {
result[key] = parent[key];
}
}
return result;
}
function getIconsTree(data, names) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
const resolved = /* @__PURE__ */ Object.create(null);
function resolve(name) {
if (icons[name]) {
return resolved[name] = [];
}
if (!(name in resolved)) {
resolved[name] = null;
const parent = aliases[name] && aliases[name].parent;
const value = parent && resolve(parent);
if (value) {
resolved[name] = [parent].concat(value);
}
}
return resolved[name];
}
(names || Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);
return resolved;
}
function internalGetIconData(data, name, tree) {
const icons = data.icons;
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
let currentProps = {};
function parse(name2) {
currentProps = mergeIconData(
icons[name2] || aliases[name2],
currentProps
);
}
parse(name);
tree.forEach(parse);
return mergeIconData(data, currentProps);
}
function parseIconSet(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") {
return names;
}
if (data.not_found instanceof Array) {
data.not_found.forEach((name) => {
callback(name, null);
names.push(name);
});
}
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
const optionalPropertyDefaults = {
provider: "",
aliases: {},
not_found: {},
...defaultIconDimensions
};
function checkOptionalProps(item, defaults) {
for (const prop in defaults) {
if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
return false;
}
}
return true;
}
function quicklyValidateIconSet(obj) {
if (typeof obj !== "object" || obj === null) {
return null;
}
const data = obj;
if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
return null;
}
if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
return null;
}
const icons = data.icons;
for (const name in icons) {
const icon = icons[name];
if (!name.match(matchIconName) || typeof icon.body !== "string" || !checkOptionalProps(
icon,
defaultExtendedIconProps
)) {
return null;
}
}
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
for (const name in aliases) {
const icon = aliases[name];
const parent = icon.parent;
if (!name.match(matchIconName) || typeof parent !== "string" || !icons[parent] && !aliases[parent] || !checkOptionalProps(
icon,
defaultExtendedIconProps
)) {
return null;
}
}
return data;
}
const dataStorage = /* @__PURE__ */ Object.create(null);
function newStorage(provider, prefix) {
return {
provider,
prefix,
icons: /* @__PURE__ */ Object.create(null),
missing: /* @__PURE__ */ new Set()
};
}
function getStorage(provider, prefix) {
const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));
return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));
}
function addIconSet(storage2, data) {
if (!quicklyValidateIconSet(data)) {
return [];
}
return parseIconSet(data, (name, icon) => {
if (icon) {
storage2.icons[name] = icon;
} else {
storage2.missing.add(name);
}
});
}
function addIconToStorage(storage2, name, icon) {
try {
if (typeof icon.body === "string") {
storage2.icons[name] = { ...icon };
return true;
}
} catch (err) {
}
return false;
}
let simpleNames = false;
function allowSimpleNames(allow) {
if (typeof allow === "boolean") {
simpleNames = allow;
}
return simpleNames;
}
function getIconData(name) {
const icon = typeof name === "string" ? stringToIcon(name, true, simpleNames) : name;
if (icon) {
const storage2 = getStorage(icon.provider, icon.prefix);
const iconName = icon.name;
return storage2.icons[iconName] || (storage2.missing.has(iconName) ? null : void 0);
}
}
function addIcon(name, data) {
const icon = stringToIcon(name, true, simpleNames);
if (!icon) {
return false;
}
const storage2 = getStorage(icon.provider, icon.prefix);
return addIconToStorage(storage2, icon.name, data);
}
function addCollection(data, provider) {
if (typeof data !== "object") {
return false;
}
if (typeof provider !== "string") {
provider = data.provider || "";
}
if (simpleNames && !provider && !data.prefix) {
let added = false;
if (quicklyValidateIconSet(data)) {
data.prefix = "";
parseIconSet(data, (name, icon) => {
if (icon && addIcon(name, icon)) {
added = true;
}
});
}
return added;
}
const prefix = data.prefix;
if (!validateIconName({
provider,
prefix,
name: "a"
})) {
return false;
}
const storage2 = getStorage(provider, prefix);
return !!addIconSet(storage2, data);
}
const defaultIconSizeCustomisations = Object.freeze({
width: null,
height: null
});
const defaultIconCustomisations = Object.freeze({
// Dimensions
...defaultIconSizeCustomisations,
// Transformations
...defaultIconTransformations
});
const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
function calculateSize(size, ratio, precision) {
if (ratio === 1) {
return size;
}
precision = precision || 100;
if (typeof size === "number") {
return Math.ceil(size * ratio * precision) / precision;
}
if (typeof size !== "string") {
return size;
}
const oldParts = size.split(unitsSplit);
if (oldParts === null || !oldParts.length) {
return size;
}
const newParts = [];
let code = oldParts.shift();
let isNumber = unitsTest.test(code);
while (true) {
if (isNumber) {
const num = parseFloat(code);
if (isNaN(num)) {
newParts.push(code);
} else {
newParts.push(Math.ceil(num * ratio * precision) / precision);
}
} else {
newParts.push(code);
}
code = oldParts.shift();
if (code === void 0) {
return newParts.join("");
}
isNumber = !isNumber;
}
}
const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
function iconToSVG(icon, customisations) {
const fullIcon = {
...defaultIconProps,
...icon
};
const fullCustomisations = {
...defaultIconCustomisations,
...customisations
};
const box = {
left: fullIcon.left,
top: fullIcon.top,
width: fullIcon.width,
height: fullIcon.height
};
let body = fullIcon.body;
[fullIcon, fullCustomisations].forEach((props) => {
const transformations = [];
const hFlip = props.hFlip;
const vFlip = props.vFlip;
let rotation = props.rotate;
if (hFlip) {
if (vFlip) {
rotation += 2;
} else {
transformations.push(
"translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
);
transformations.push("scale(-1 1)");
box.top = box.left = 0;
}
} else if (vFlip) {
transformations.push(
"translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
);
transformations.push("scale(1 -1)");
box.top = box.left = 0;
}
let tempValue;
if (rotation < 0) {
rotation -= Math.floor(rotation / 4) * 4;
}
rotation = rotation % 4;
switch (rotation) {
case 1:
tempValue = box.height / 2 + box.top;
transformations.unshift(
"rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
case 2:
transformations.unshift(
"rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
);
break;
case 3:
tempValue = box.width / 2 + box.left;
transformations.unshift(
"rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
);
break;
}
if (rotation % 2 === 1) {
if (box.left !== box.top) {
tempValue = box.left;
box.left = box.top;
box.top = tempValue;
}
if (box.width !== box.height) {
tempValue = box.width;
box.width = box.height;
box.height = tempValue;
}
}
if (transformations.length) {
body = '
").replace(/\s/g, none.value);
});
const disabled = vue.computed(() => {
if (content.value) {
return content.value === replyInfo;
} else {
return true;
}
});
function drop(e2) {
e2.preventDefault();
upload(e2.dataTransfer.files[0]);
}
async function upload(file) {
if (!file)
return;
if (uploadLoading.value)
return;
uploadLoading.value = true;
const formData = new FormData();
formData.append("image", file);
const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
const clidenId = imgurClientIdPool[randomIndex];
const res = await fetch("https://api.imgur.com/3/upload", {
method: "POST",
headers: { Authorization: `Client-ID ${clidenId}` },
body: formData
});
uploadLoading.value = false;
if (res.ok) {
const resData = await res.json();
if (resData.success) {
return insert(" " + resData.data.link + " ");
}
}
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "上传失败" });
}
async function submit() {
if (disabled.value || loading.value)
return;
loading.value = true;
let submit_content = content.value.replace(/\[((?!\[).)+\]/g, function(match) {
let item2 = classicsEmoticons.find((v) => v.name === match);
if (item2) {
return item2.low + " ";
}
return match;
});
let show_content = content.value.replace(/https?:\/\/(i\.)?imgur\.com\/((?!http).)+\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)/g, function(match) {
return ``;
});
show_content = show_content.replace(/\[((?!\[).)+\]/g, function(match) {
let item2 = classicsEmoticons.find((v) => v.name === match);
if (item2) {
return `
`;
}
return match;
});
let matchUsers = show_content.match(/@([\w]+?[\s])/g);
if (matchUsers) {
matchUsers.map((i) => {
let username = i.replace("@", "").replace(" ", "");
show_content = show_content.replace(username, `${username}`);
});
}
show_content = show_content.replaceAll("\n", "
");
let item = {
thankCount: 0,
isThanked: false,
isOp: post.value.username === window.user.username,
isDup: false,
id: Date.now(),
username: window.user.username,
avatar: window.user.avatar,
date: "几秒前",
floor: post.value.replyCount + 1,
reply_content: show_content ?? "",
children: [],
replyUsers: replyUser ? [replyUser] : [],
replyFloor: replyFloor || -1,
level: useType === "reply-comment" ? 1 : 0
};
item.hideCallUserReplyContent = item.reply_content;
if (item.replyUsers.length === 1) {
item.hideCallUserReplyContent = item.reply_content.replace(/@ {
loading.value = false;
let r2 = res.search("你上一条回复的内容和这条相同");
if (r2 > -1)
return eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你上一条回复的内容和这条相同" });
r2 = res.search("请不要在每一个回复中都包括外链,这看起来像是在 spamming");
if (r2 > -1)
return eventBus.emit(CMD.SHOW_MSG, {
type: "error",
text: "请不要在每一个回复中都包括外链,这看起来像是在 spamming"
});
let r22 = res.search("创建新回复");
if (r22 > -1) {
eventBus.emit(CMD.REFRESH_ONCE, res);
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复出现了问题,请使用原版进行回复" });
let clientWidth = window.document.body.clientWidth;
let windowWidth = 1200;
let left = clientWidth / 2 - windowWidth / 2;
let newWin = window.open("创建新回复", "", `width=${windowWidth},height=600,left=${left},top=100`);
newWin.document.write(res);
let loop = setInterval(function() {
if (newWin.closed) {
clearInterval(loop);
eventBus.emit(CMD.REFRESH_POST);
}
}, 1e3);
return;
}
content.value = replyInfo;
emits("close");
eventBus.emit(CMD.REFRESH_ONCE, res);
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "回复成功" });
eventBus.emit(CMD.ADD_REPLY, item);
},
(err) => {
console.log("err", err);
loading.value = false;
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
}
).catch((r2) => {
console.log("catch", r2);
});
}
function showEmoticons(e2) {
if (isShowEmoticons.value) {
return isShowEmoticons.value = false;
}
let rect = e2.currentTarget.getBoundingClientRect();
emoticonsRef.value.style.left = rect.left + 30 + "px";
emoticonsRef.value.style.bottom = window.innerHeight - rect.top - 20 + "px";
isShowEmoticons.value = true;
}
function off() {
eventBus.emit(CMD.SHOW_CALL, { show: false });
eventBus.off(CMD.SET_CALL);
}
function checkHeight2() {
txtRef.value.style.height = 0;
txtRef.value.style.height = txtRef.value.scrollHeight + "px";
}
function insert(str) {
let cursorPos = txtRef.value.selectionStart;
let start = content.value.slice(0, cursorPos);
let end = content.value.slice(cursorPos, content.value.length);
content.value = start + str + end;
let moveCursorPos = start.length + str.length;
setTimeout(() => {
txtRef.value.focus();
txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
checkHeight2();
});
}
function showCallPopover(text) {
let r2 = cursorRef.value.getBoundingClientRect();
eventBus.emit(CMD.SHOW_CALL, { show: true, top: r2.top, left: r2.left, text });
eventBus.off(CMD.SET_CALL);
eventBus.on(CMD.SET_CALL, (e2) => {
let cursorPos = txtRef.value.selectionStart;
let start = content.value.slice(0, cursorPos);
let end = content.value.slice(cursorPos, content.value.length);
let lastCallPos = start.lastIndexOf("@");
start = content.value.slice(0, lastCallPos + 1);
if (e2 === "管理员") {
e2 = "Livid @Kai @Olivia @GordianZ @sparanoid";
}
if (e2 === "所有人") {
e2 = allReplyUsers.value.map((v, i) => {
if (i)
return "@" + v;
else
return v;
}).join(" ");
}
content.value = start + e2 + " " + end;
let moveCursorPos = start.length + e2.length + 1;
setTimeout(() => {
txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
checkHeight2();
});
eventBus.off(CMD.SET_CALL);
});
}
function onKeydown(e2) {
let code = e2.keyCode;
switch (code) {
case 8:
if (content.value === "@") {
off();
}
break;
case 37:
case 38:
case 39:
case 40:
setTimeout(() => onInput({ data: "" }), 100);
break;
case 27:
e2.preventDefault();
e2.stopPropagation();
e2.stopImmediatePropagation();
return false;
case 13:
if (e2.ctrlKey)
submit();
if (e2.metaKey)
submit();
break;
}
}
function onInput(e2) {
let cursorPos = txtRef.value.selectionStart;
if (!content.value)
return;
if (e2.data === " ") {
return off();
}
if (e2.data === "@") {
if (content.value.length !== 1) {
if (content.value[cursorPos - 2] === " " || content.value[cursorPos - 2] === "\n") {
return showCallPopover("");
}
} else {
return showCallPopover("");
}
off();
} else {
let judgeStr = content.value.slice(0, cursorPos);
let lastCallPos = judgeStr.lastIndexOf("@");
if (lastCallPos === -1) {
return off();
}
let callStr = judgeStr.slice(lastCallPos, cursorPos);
let hasSpace = callStr.includes(" ");
if (hasSpace) {
off();
} else {
if (lastCallPos === 0) {
return showCallPopover(callStr.replace("@", ""));
}
if (content.value.length !== 1) {
if (content.value[lastCallPos - 1] === " " || content.value[lastCallPos - 1] === "\n") {
return showCallPopover(callStr.replace("@", ""));
}
} else {
return showCallPopover(callStr.replace("@", ""));
}
off();
}
}
}
function onPaste(e2) {
const dataTransferItemList = e2.clipboardData.items;
const items = [].slice.call(dataTransferItemList).filter(function(item) {
return item.type.indexOf("image") !== -1;
});
if (items.length === 0) {
return;
}
const dataTransferItem = items[0];
const blob = dataTransferItem.getAsFile();
upload(blob);
}
function onBlur() {
document.removeEventListener("paste", onPaste);
isFocus.value = false;
}
function onFocusin() {
document.addEventListener("paste", onPaste);
}
vue.watch(() => show, (n2) => {
if (n2.value)
isShowEmoticons.value = false;
}, { deep: true });
vue.onMounted(() => {
$(`.${editorId.value}`).each(function() {
this.setAttribute("style", "height:" + this.scrollHeight + "px;overflow-y:hidden;");
}).on("input", function() {
this.style.height = 0;
this.style.height = this.scrollHeight + "px";
});
if (useType === "reply-comment") {
txtRef.value && txtRef.value.focus();
}
});
vue.onBeforeUnmount(() => {
$(`.${editorId.value}`).off();
});
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["post-editor-wrapper", editorClass.value])
}, [
vue.withDirectives(vue.createElementVNode("textarea", {
class: vue.normalizeClass(["post-editor", editorId.value]),
ref_key: "txtRef",
ref: txtRef,
onFocus: _cache[0] || (_cache[0] = ($event) => vue.isRef(isFocus) ? isFocus.value = true : isFocus = true),
onBlur,
onFocusin,
placeholder: "请尽量让自己的回复能够对别人有帮助",
onInput,
onKeydown,
onDrop: drop,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => content.value = $event)
}, null, 34), [
[vue.vModelText, content.value]
]),
vue.createElementVNode("div", _hoisted_1$b, [
vue.createElementVNode("span", { innerHTML: cursorHtml.value }, null, 8, _hoisted_2$8),
vue.createElementVNode("span", {
class: "cursor",
ref_key: "cursorRef",
ref: cursorRef
}, "|", 512)
]),
vue.createElementVNode("div", _hoisted_3$7, [
vue.createElementVNode("div", _hoisted_4$7, [
vue.createVNode(vue.unref(Icon), {
onClick: showEmoticons,
icon: "streamline:smiley-happy"
}),
vue.createElementVNode("div", _hoisted_5$5, [
vue.createElementVNode("input", {
type: "file",
accept: "image/*",
onChange: _cache[2] || (_cache[2] = (e2) => upload(e2.currentTarget.files[0]))
}, null, 32),
vue.createVNode(vue.unref(Icon), { icon: "lets-icons:img-load-box-fill" })
]),
uploadLoading.value ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_6$5, "上传中.....")) : vue.createCommentVNode("", true)
]),
vue.createElementVNode("div", _hoisted_7$4, [
vue.unref(useType) === "reply-comment" ? (vue.openBlock(), vue.createBlock(BaseButton, {
key: 0,
type: "link",
size: "small",
style: { "margin-right": "1rem", "cursor": "pointer" },
onClick: _cache[3] || (_cache[3] = ($event) => emits("close"))
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 关闭 ")
]),
_: 1
})) : vue.createCommentVNode("", true),
vue.createVNode(BaseButton, {
size: "small",
disabled: disabled.value,
loading: loading.value,
onClick: submit
}, {
default: vue.withCtx(() => [
vue.createTextVNode("回复 ")
]),
_: 1
}, 8, ["disabled", "loading"])
])
]),
vue.withDirectives(vue.createElementVNode("div", {
class: "emoticon-pack",
ref_key: "emoticonsRef",
ref: emoticonsRef
}, [
vue.createVNode(vue.unref(Icon), {
icon: "ic:round-close",
onClick: _cache[4] || (_cache[4] = ($event) => isShowEmoticons.value = false)
}),
_hoisted_8$4,
vue.createElementVNode("div", _hoisted_9$4, [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(classicsEmoticons, (item) => {
return vue.createElementVNode("img", {
src: item.high,
onClick: ($event) => {
insert(item.name);
isShowEmoticons.value = false;
}
}, null, 8, _hoisted_10$3);
}), 64))
]),
vue.createElementVNode("div", _hoisted_11$3, [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(emojiEmoticons, (item) => {
return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
vue.createElementVNode("div", _hoisted_12$3, vue.toDisplayString(item.title), 1),
vue.createElementVNode("div", _hoisted_13$3, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.list, (emoji) => {
return vue.openBlock(), vue.createElementBlock("span", {
onClick: ($event) => {
insert(emoji);
isShowEmoticons.value = false;
}
}, vue.toDisplayString(emoji), 9, _hoisted_14$3);
}), 256))
])
], 64);
}), 64))
])
], 512), [
[vue.vShow, isShowEmoticons.value]
])
], 2);
};
}
};
const PostEditor = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-4522f98e"]]);
const _hoisted_1$a = {
key: 0,
class: "html-wrapper"
};
const _hoisted_2$7 = ["innerHTML"];
const checkHeight = 900;
const _sfc_main$a = {
__name: "BaseHtmlRender",
props: ["html"],
setup(__props) {
const config2 = vue.inject("config");
const props = __props;
const contentRef = vue.ref(null);
const mask = vue.ref(false);
const handOpen = vue.ref(false);
function mouseup(e2) {
if (!config2.value.base64)
return;
let selectionText = window.win().getSelection().toString();
if (selectionText) {
let r2 = selectionText.match(/([A-Za-z0-9+/=]+)/g);
if (r2) {
if (r2[0].length < 4)
return;
eventBus.emit(CMD.SHOW_TOOLTIP, { text: r2[0], e: e2 });
}
}
}
vue.watch(config2.value, (newVale) => {
if (!newVale.contentAutoCollapse) {
mask.value = false;
}
});
vue.watch([() => contentRef.value, () => props.html], () => {
if (!contentRef.value || !props.html)
return;
if (!config2.value.contentAutoCollapse)
return;
contentRef.value.querySelectorAll("img").forEach((item) => {
item.removeEventListener("load", checkContentHeight);
item.addEventListener("load", checkContentHeight);
});
checkContentHeight();
}, { immediate: true, flush: "post" });
function checkContentHeight() {
if (handOpen.value)
return;
let rect = contentRef.value.getBoundingClientRect();
mask.value = rect.height >= checkHeight;
}
return (_ctx, _cache) => {
return props.html ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$a, [
vue.createElementVNode("div", {
class: vue.normalizeClass({ mask: mask.value })
}, [
vue.createElementVNode("div", {
ref_key: "contentRef",
ref: contentRef,
innerHTML: props.html,
onMouseup: mouseup
}, null, 40, _hoisted_2$7)
], 2),
mask.value ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
class: "expand",
onClick: _cache[0] || (_cache[0] = ($event) => {
mask.value = false;
handOpen.value = true;
})
}, "展开")) : vue.createCommentVNode("", true)
])) : vue.createCommentVNode("", true);
};
}
};
const BaseHtmlRender = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-2c9a538c"]]);
const _sfc_main$9 = {
name: "Comment",
components: { BaseHtmlRender, Author, PostEditor, Point },
inject: ["post", "postDetailWidth", "show", "isNight", "config"],
props: {
modelValue: {
reply_content: ""
},
type: {
type: String,
default() {
return "list";
}
}
},
data() {
return {
showOrigin: false,
edit: false,
ding: false,
expand: true,
expandWrong: false,
replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
cssStyle: null,
floor: this.modelValue.floor
};
},
watch: {
show(e2) {
if (e2) {
this.edit = false;
}
},
postDetailWidth(n2, o) {
this.checkIsTooLong(n2);
}
},
computed: {
CommentDisplayType() {
return CommentDisplayType;
},
myClass() {
return {
isOp: this.modelValue.isOp,
isSimple: this.config.viewType === "simple",
ding: this.ding,
isLevelOne: this.modelValue.level === 0,
["c_" + this.floor]: this.type !== "top"
};
}
},
mounted() {
this.checkIsTooLong(this.postDetailWidth);
},
methods: {
checkIsTooLong(postDetailWidth) {
if (postDetailWidth !== 0) {
let rect = this.$refs.comment.getBoundingClientRect();
let ban = postDetailWidth / 2;
if (ban < rect.width && rect.width < ban + 25 && this.modelValue.children.length) {
this.expand = false;
let padding = 2;
this.cssStyle = {
padding: "1rem 0",
width: `calc(${postDetailWidth}px - ${padding}rem)`,
transform: `translateX(calc(${rect.width - postDetailWidth}px + ${padding}rem))`,
background: this.isNight ? "#18222d" : "white"
};
}
}
},
//高亮一下
showDing() {
this.ding = true;
setTimeout(() => {
this.ding = false;
}, 2e3);
},
hide() {
let url = `${window.baseUrl}/ignore/reply/${this.modelValue.id}?once=${this.post.once}`;
eventBus.emit(CMD.REMOVE, this.modelValue.floor);
$.post(url).then((res) => {
eventBus.emit(CMD.REFRESH_ONCE);
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "隐藏成功" });
}, (err) => {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "隐藏成功,仅本次有效(接口调用失败!)" });
});
},
toggle() {
this.expand = !this.expand;
},
toggleContent() {
if (this.modelValue.level === 0 && this.modelValue.replyUsers.length === 0)
return;
this.showOrigin = !this.showOrigin;
}
}
};
const _withScopeId$6 = (n2) => (vue.pushScopeId("data-v-888958af"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$9 = ["data-floor"];
const _hoisted_2$6 = { class: "comment-content" };
const _hoisted_3$6 = { class: "right" };
const _hoisted_4$6 = { class: "w" };
const _hoisted_5$4 = {
key: 0,
class: "wrong-wrapper"
};
const _hoisted_6$4 = ["href"];
const _hoisted_7$3 = { class: "del-line" };
const _hoisted_8$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("i", {
class: "fa fa-question-circle-o wrong-icon",
"aria-hidden": "true"
}, null, -1));
const _hoisted_9$3 = {
key: 0,
class: "warning"
};
const _hoisted_10$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_11$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_12$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_13$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_14$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_15$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("a", {
href: "https://github.com/zyronon/web-scripts/issues",
target: "_blank"
}, "这里", -1));
const _hoisted_16$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("p", null, "---原文---", -1));
const _hoisted_17$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("p", null, "-----------", -1));
const _hoisted_18$2 = { class: "simple-wrapper" };
function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
const _component_Author = vue.resolveComponent("Author");
const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
const _component_PostEditor = vue.resolveComponent("PostEditor");
const _component_Comment = vue.resolveComponent("Comment", true);
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["comment", $options.myClass]),
ref: "comment",
"data-floor": $data.floor
}, [
vue.createVNode(_component_Author, {
modelValue: $data.expand,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
comment: $props.modelValue,
onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
type: $props.type,
onHide: $options.hide
}, null, 8, ["modelValue", "comment", "type", "onHide"]),
$data.cssStyle && !$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
class: "more ago",
onClick: _cache[2] || (_cache[2] = ($event) => $data.expand = !$data.expand)
}, " 由于嵌套回复层级太深,自动将后续回复隐藏 ")) : vue.createCommentVNode("", true),
$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
key: 1,
class: "comment-content-w",
style: vue.normalizeStyle($data.cssStyle)
}, [
$data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
class: "more ago",
onClick: _cache[3] || (_cache[3] = ($event) => $data.expand = !$data.expand)
}, " 由于嵌套回复层级太深,自动将以下回复移至可见范围 ")) : vue.createCommentVNode("", true),
vue.createElementVNode("div", _hoisted_2$6, [
vue.createElementVNode("div", {
class: "left expand-line",
onClick: _cache[4] || (_cache[4] = (...args) => $options.toggle && $options.toggle(...args))
}),
vue.createElementVNode("div", _hoisted_3$6, [
vue.createElementVNode("div", _hoisted_4$6, [
$props.modelValue.isWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$4, [
vue.createElementVNode("span", {
onClick: _cache[5] || (_cache[5] = ($event) => $data.expandWrong = !$data.expandWrong),
title: "点击楼层号查看提示"
}, [
vue.createElementVNode("a", {
href: "/member/" + $props.modelValue.replyUsers[0]
}, "@" + vue.toDisplayString($props.modelValue.replyUsers[0]) + " ", 9, _hoisted_6$4),
vue.createElementVNode("span", _hoisted_7$3, "#" + vue.toDisplayString($props.modelValue.replyFloor), 1),
_hoisted_8$3
]),
$data.expandWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$3, [
vue.createTextVNode(" 这条回复似乎有点问题,指定的楼层号与@的人对应不上 "),
_hoisted_10$2,
vue.createTextVNode(" 原因可能有下面几种: "),
_hoisted_11$2,
vue.createTextVNode(" 一、屏蔽用户导致楼层塌陷:你屏蔽了A,自A以后的回复的楼层号都会减1 "),
_hoisted_12$2,
vue.createTextVNode(" 二、忽略回复导致楼层塌陷:原理同上 "),
_hoisted_13$2,
vue.createTextVNode(" 三、层主回复时指定错了楼层号(同一,层主屏蔽了别人,导致楼层塌陷) "),
_hoisted_14$2,
vue.createTextVNode(" 四、脚本解析错误,请在 "),
_hoisted_15$2,
vue.createTextVNode("反馈 ")
])) : vue.createCommentVNode("", true)
])) : vue.createCommentVNode("", true),
$options.config.commentDisplayType === $options.CommentDisplayType.FloorInFloorNoCallUser && this.type !== "top" ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
$data.showOrigin ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
onDblclick: _cache[6] || (_cache[6] = (...args) => $options.toggleContent && $options.toggleContent(...args))
}, [
_hoisted_16$2,
vue.createVNode(_component_BaseHtmlRender, {
class: "reply_content",
html: $props.modelValue.reply_content
}, null, 8, ["html"]),
_hoisted_17$2
], 32)) : vue.createCommentVNode("", true),
vue.createVNode(_component_BaseHtmlRender, {
class: "reply_content",
onDblclick: $options.toggleContent,
html: $props.modelValue.hideCallUserReplyContent
}, null, 8, ["onDblclick", "html"])
], 64)) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
key: 2,
class: "reply_content",
html: $props.modelValue.reply_content
}, null, 8, ["html"])),
$data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
key: 3,
onClose: _cache[7] || (_cache[7] = ($event) => $data.edit = false),
replyInfo: $data.replyInfo,
replyUser: $props.modelValue.username,
replyFloor: $props.modelValue.floor
}, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true)
]),
vue.createElementVNode("div", _hoisted_18$2, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index) => {
return vue.openBlock(), vue.createBlock(_component_Comment, {
modelValue: $props.modelValue.children[index],
"onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
key: index
}, null, 8, ["modelValue", "onUpdate:modelValue"]);
}), 128))
])
])
]),
$data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
key: 1,
class: "more ago",
onClick: _cache[8] || (_cache[8] = ($event) => $data.expand = !$data.expand)
}, " 由于嵌套回复层级太深,自动将以上回复移至可见范围 ")) : vue.createCommentVNode("", true)
], 4)) : vue.createCommentVNode("", true)
], 10, _hoisted_1$9);
}
const Comment = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$4], ["__scopeId", "data-v-888958af"]]);
const _sfc_main$8 = {
name: "Toolbar",
components: { Icon, BaseLoading },
inject: [
"isLogin",
"post",
"pageType"
],
data() {
return {
timer: null,
loading: false,
loading2: false,
loading3: false
};
},
methods: {
checkIsLogin(emitName = "") {
if (!this.isLogin) {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
return false;
}
this.$emit(emitName);
return true;
},
tweet() {
var _a;
let username = ((_a = window.user) == null ? void 0 : _a.username) ?? "";
let url = `https://twitter.com/intent/tweet?url=${location.origin}/t/${this.post.id}?r=${username}&related=v2ex&text=${this.post.title}`;
window.open(url, "_blank", "width=550,height=370");
},
async report() {
if (!this.checkIsLogin())
return;
if (this.loading3)
return;
let isReport = this.post.isReport;
if (isReport) {
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
return;
}
let url = `${location.origin}/report/topic/${this.post.id}?once=${this.post.once}`;
this.loading3 = true;
let apiRes = await fetch(url);
this.loading3 = false;
if (apiRes.redirected) {
let htmlText = await apiRes.text();
if (htmlText.search("你已对本主题进行了报告")) {
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
eventBus.emit(CMD.REFRESH_ONCE, htmlText);
eventBus.emit(CMD.MERGE, { isReport: !isReport });
return;
}
}
eventBus.emit(CMD.REFRESH_ONCE);
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败,请重试" });
},
async toggleIgnore() {
if (!this.checkIsLogin())
return;
let url = `${window.baseUrl}/${this.post.isIgnore ? "unignore" : "ignore"}/topic/${this.post.id}?once=${this.post.once}`;
if (this.pageType === PageType.Post) {
this.loading2 = true;
let apiRes = await window.win().fetch(url);
if (apiRes.redirected) {
if (!this.post.isIgnore) {
window.win().location = window.baseUrl;
}
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
} else {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略失败" });
}
this.loading2 = false;
} else {
if (this.post.isIgnore) {
this.loading2 = true;
} else {
eventBus.emit(CMD.IGNORE);
}
let apiRes = await window.win().fetch(url);
if (apiRes.redirected) {
if (this.post.isIgnore) {
eventBus.emit(CMD.REFRESH_ONCE);
}
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
} else {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略成功,仅本次有效(接口调用失败!)" });
}
this.loading2 = false;
}
},
async toggleFavorite() {
if (!this.checkIsLogin())
return;
if (this.loading)
return;
let isFavorite = this.post.isFavorite;
if (!isFavorite && config.collectBrowserNotice) {
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "别忘记按Command/Cmd/CTRL + D添加到书签哦" });
}
let url = `${location.origin}/${isFavorite ? "unfavorite" : "favorite"}/topic/${this.post.id}?once=${this.post.once}`;
this.loading = true;
let apiRes = await fetch(url);
this.loading = false;
if (apiRes.redirected) {
let htmlText = await apiRes.text();
if (htmlText.search(isFavorite ? "加入收藏" : "取消收藏")) {
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: isFavorite ? "取消成功" : "收藏成功" });
eventBus.emit(CMD.MERGE, { collectCount: isFavorite ? this.post.collectCount - 1 : this.post.collectCount + 1 });
eventBus.emit(CMD.REFRESH_ONCE, htmlText);
eventBus.emit(CMD.MERGE, { isFavorite: !isFavorite });
return;
}
}
eventBus.emit(CMD.REFRESH_ONCE);
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败" });
}
}
};
const _withScopeId$5 = (n2) => (vue.pushScopeId("data-v-e3df61b2"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$8 = { class: "toolbar" };
const _hoisted_2$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复", -1));
const _hoisted_3$5 = {
key: 0,
class: "tool no-hover"
};
const _hoisted_4$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "Tweet", -1));
function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
const _component_Icon = vue.resolveComponent("Icon");
const _component_BaseLoading = vue.resolveComponent("BaseLoading");
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
vue.renderSlot(_ctx.$slots, "default", {}, void 0, true),
vue.createElementVNode("div", {
class: "tool",
onClick: _cache[0] || (_cache[0] = ($event) => $options.checkIsLogin("reply"))
}, [
vue.createVNode(_component_Icon, { icon: "mynaui:message" }),
_hoisted_2$5
]),
vue.createElementVNode("div", {
class: vue.normalizeClass(["tool", { disabled: $data.loading }]),
onClick: _cache[1] || (_cache[1] = (...args) => $options.toggleFavorite && $options.toggleFavorite(...args))
}, [
$data.loading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
key: 0,
size: "small"
})) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
$options.post.isFavorite ? (vue.openBlock(), vue.createBlock(_component_Icon, {
key: 0,
color: "rgb(224,42,42)",
icon: "iconoir:star-solid"
})) : (vue.openBlock(), vue.createBlock(_component_Icon, {
key: 1,
icon: "iconoir:star"
}))
], 64)),
vue.createElementVNode("span", null, vue.toDisplayString($options.post.isFavorite ? "取消" : "") + "收藏", 1)
], 2),
$options.post.collectCount !== 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$5, [
vue.createElementVNode("span", null, vue.toDisplayString($options.post.collectCount + "人收藏"), 1)
])) : vue.createCommentVNode("", true),
vue.createElementVNode("div", {
class: "tool",
onClick: _cache[2] || (_cache[2] = (...args) => $options.tweet && $options.tweet(...args))
}, [
vue.createVNode(_component_Icon, { icon: "uil:share" }),
_hoisted_4$5
]),
vue.createElementVNode("div", {
class: vue.normalizeClass(["tool", { "disabled": $data.loading2 }]),
onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleIgnore && $options.toggleIgnore(...args))
}, [
$data.loading2 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
key: 0,
size: "small"
})) : (vue.openBlock(), vue.createBlock(_component_Icon, {
key: 1,
icon: "fluent:eye-hide-24-regular"
})),
vue.createElementVNode("span", null, vue.toDisplayString($options.post.isIgnore ? "取消忽略" : "忽略"), 1)
], 2),
vue.createElementVNode("div", {
class: vue.normalizeClass(["tool", { "disabled": $data.loading3 }]),
onClick: _cache[4] || (_cache[4] = (...args) => $options.report && $options.report(...args))
}, [
$data.loading3 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
key: 0,
size: "small"
})) : (vue.openBlock(), vue.createBlock(_component_Icon, {
key: 1,
class: "black",
icon: "solar:danger-triangle-outline"
})),
vue.createElementVNode("span", null, vue.toDisplayString($options.post.isReport ? "你已对本主题进行了报告" : "报告"), 1)
], 2)
]);
}
const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$3], ["__scopeId", "data-v-e3df61b2"]]);
const _withScopeId$4 = (n2) => (vue.pushScopeId("data-v-87050bc7"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$7 = ["href"];
const _hoisted_2$4 = ["src"];
const _hoisted_3$4 = { class: "texts" };
const _hoisted_4$4 = {
key: 0,
class: "point"
};
const _hoisted_5$3 = { class: "link-num" };
const _hoisted_6$3 = { class: "my-tag" };
const _hoisted_7$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
const _hoisted_8$2 = {
key: 2,
class: "ago"
};
const _hoisted_9$2 = {
key: 3,
class: "mod"
};
const _hoisted_10$1 = {
key: 4,
class: "owner"
};
const _hoisted_11$1 = ["href"];
const _hoisted_12$1 = {
key: 5,
class: "owner"
};
const _hoisted_13$1 = {
key: 6,
class: "mod"
};
const _hoisted_14$1 = {
key: 7,
class: "ago"
};
const _hoisted_15$1 = { class: "my-tag" };
const _hoisted_16$1 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
const _hoisted_17$1 = {
key: 9,
class: "point"
};
const _hoisted_18$1 = { class: "link-num" };
const _hoisted_19$1 = ["href"];
const _hoisted_20$1 = ["src"];
const _hoisted_21$1 = { class: "Author-right" };
const _hoisted_22$1 = { class: "floor" };
const _hoisted_23$1 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
const _hoisted_24$1 = [
_hoisted_23$1
];
const _sfc_main$7 = {
__name: "SingleComment",
props: {
comment: {
reply_content: ""
},
isRight: {
type: Boolean,
default() {
return false;
}
}
},
setup(__props) {
const config2 = vue.inject("config");
const isLogin = vue.inject("isLogin");
const tags = vue.inject("tags");
const props = __props;
const myTags = vue.computed(() => {
return tags[props.comment.username] ?? [];
});
function jump() {
eventBus.emit(CMD.JUMP, props.comment.floor);
}
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["comment", { isSimple: vue.unref(config2).viewType === "simple" }]),
ref: "comment"
}, [
!__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
key: 0,
class: "avatar",
href: `/member/${__props.comment.username}`
}, [
vue.createElementVNode("img", {
src: __props.comment.avatar,
alt: ""
}, null, 8, _hoisted_2$4)
], 8, _hoisted_1$7)) : vue.createCommentVNode("", true),
vue.createElementVNode("div", {
class: vue.normalizeClass(["comment-body", { isRight: __props.isRight }])
}, [
vue.createElementVNode("div", _hoisted_3$4, [
__props.comment.thankCount && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, [
__props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
key: 0,
color: "rgb(224,42,42)",
icon: "icon-park-solid:like"
})) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
key: 1,
color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
icon: "icon-park-outline:like"
}, null, 8, ["color"])),
vue.createElementVNode("div", _hoisted_5$3, vue.toDisplayString(__props.comment.thankCount), 1)
])) : vue.createCommentVNode("", true),
vue.unref(isLogin) && vue.unref(config2).openTag && __props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(myTags.value, (i) => {
return vue.openBlock(), vue.createElementBlock("span", _hoisted_6$3, [
_hoisted_7$2,
vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
]);
}), 256)) : vue.createCommentVNode("", true),
__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_8$2, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
__props.comment.isMod && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$2, "MOD")) : vue.createCommentVNode("", true),
__props.comment.isOp && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$1, "OP")) : vue.createCommentVNode("", true),
vue.createElementVNode("a", {
href: `/member/${__props.comment.username}`,
class: "username"
}, vue.toDisplayString(__props.comment.username), 9, _hoisted_11$1),
__props.comment.isOp && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$1, "OP")) : vue.createCommentVNode("", true),
__props.comment.isMod && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$1, "MOD")) : vue.createCommentVNode("", true),
!__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_14$1, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
vue.unref(isLogin) && vue.unref(config2).openTag && !__props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 8 }, vue.renderList(myTags.value, (i) => {
return vue.openBlock(), vue.createElementBlock("span", _hoisted_15$1, [
_hoisted_16$1,
vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
]);
}), 256)) : vue.createCommentVNode("", true),
__props.comment.thankCount && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_17$1, [
__props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
key: 0,
color: "rgb(224,42,42)",
icon: "icon-park-solid:like"
})) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
key: 1,
color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
icon: "icon-park-outline:like"
}, null, 8, ["color"])),
vue.createElementVNode("div", _hoisted_18$1, vue.toDisplayString(__props.comment.thankCount), 1)
])) : vue.createCommentVNode("", true)
]),
vue.createVNode(BaseHtmlRender, {
class: "reply_content",
html: __props.comment.reply_content
}, null, 8, ["html"])
], 2),
__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
key: 1,
class: "avatar",
href: `/member/${__props.comment.username}`
}, [
vue.createElementVNode("img", {
src: __props.comment.avatar,
alt: ""
}, null, 8, _hoisted_20$1)
], 8, _hoisted_19$1)) : vue.createCommentVNode("", true),
vue.createElementVNode("div", _hoisted_21$1, [
vue.createElementVNode("div", _hoisted_22$1, vue.toDisplayString(__props.comment.floor), 1),
vue.createElementVNode("div", {
class: "tool jump",
onClick: jump
}, _hoisted_24$1)
])
], 2);
};
}
};
const SingleComment = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-87050bc7"]]);
const _sfc_main$6 = {
name: "detail",
components: {
BaseSelect,
BaseButton,
SingleComment,
PopConfirm,
Comment,
PostEditor,
Point,
Toolbar,
BaseHtmlRender,
Tooltip,
BaseLoading,
Icon
},
inject: ["allReplyUsers", "post", "isMobile", "tags", "isLogin", "config", "pageType", "isNight"],
provide() {
return {
postDetailWidth: vue.computed(() => this.postDetailWidth)
};
},
props: {
modelValue: {
type: Boolean,
default() {
return false;
}
},
loading: {
type: Boolean,
default() {
return false;
}
},
refreshLoading: {
type: Boolean,
default() {
return false;
}
},
displayType: CommentDisplayType.FloorInFloorNoCallUser
},
data() {
return {
isSticky: false,
selectCallIndex: 0,
postDetailWidth: 0,
showCallList: false,
showRelationReply: false,
replyText: "",
callStyle: {
top: 0,
left: 0
},
targetUser: {
left: [],
right: "",
rightFloor: -1
},
currentFloor: "",
showOpTag: false
};
},
computed: {
canAppend() {
if (this.isMy) {
let create = new Date(this.post.createDate);
return Date.now() - create.valueOf() > 1e3 * 60 * 30;
}
return false;
},
canEditMove() {
if (this.isMy) {
let create = new Date(this.post.createDate);
return Date.now() - create.valueOf() < 1e3 * 60 * 10;
}
return false;
},
isMy() {
return this.post.member.username === window.user.username;
},
myTags() {
return this.tags[this.post.member.username] ?? [];
},
CommentDisplayType() {
return CommentDisplayType;
},
isPost() {
return this.pageType === PageType.Post;
},
filterCallList() {
if (this.showCallList) {
let list = ["管理员", "所有人"].concat(this.allReplyUsers);
if (this.replyText)
return list.filter((i) => i.search(this.replyText) > -1);
return list;
}
return [];
},
topReply() {
return this.post.replyList.filter((v) => v.thankCount >= this.config.topReplyLoveMinCount).sort((a, b) => b.thankCount - a.thankCount).slice(0, this.config.topReplyCount);
},
replyList() {
if ([CommentDisplayType.FloorInFloor, CommentDisplayType.FloorInFloorNoCallUser].includes(this.displayType))
return this.post.nestedReplies;
if (this.displayType === CommentDisplayType.Like) {
return window.clone(this.post.nestedReplies).sort((a, b) => b.thankCount - a.thankCount);
}
if (this.displayType === CommentDisplayType.New) {
return window.clone(this.post.replyList).reverse();
}
if (this.displayType === CommentDisplayType.V2exOrigin)
return this.post.replyList;
if (this.displayType === CommentDisplayType.FloorInFloorNested)
return this.post.nestedRedundReplies;
if (this.displayType === CommentDisplayType.OnlyOp)
return this.post.replyList.filter((v) => {
var _a;
return v.username === ((_a = this.post.member) == null ? void 0 : _a.username);
});
return [];
},
//关联回复
relationReply() {
if (this.targetUser.left.length && this.targetUser.right) {
return this.post.replyList.filter((v) => {
if (this.targetUser.left.includes(v.username)) {
if (v.floor > this.targetUser.rightFloor) {
if (v.replyUsers.includes(this.targetUser.right)) {
return true;
}
} else {
return true;
}
}
if (v.username === this.targetUser.right) {
for (let i = 0; i < this.targetUser.left.length; i++) {
if (v.replyUsers.includes(this.targetUser.left[i])) {
return true;
}
}
}
});
}
return [];
}
},
watch: {
"post.id"(n2, o) {
if (this.$refs["post-editor"]) {
this.$refs["post-editor"].content = "";
vue.nextTick(() => {
var _a, _b;
(_b = (_a = this.$refs) == null ? void 0 : _a.detail) == null ? void 0 : _b.scrollTo({ top: 0 });
});
}
},
"post.headerTemplate"(n2, o) {
let mountEl = document.querySelector(".main-wrapper .post-wrapper .html-wrapper .header");
if (mountEl) {
this.showOpTag = true;
}
},
modelValue: {
handler(newVal) {
if (this.isPost) {
return;
}
if (newVal) {
document.body.style.overflow = "hidden";
if (!window.history.state) {
window.history.pushState({}, 0, this.post.href);
}
this.currentFloor = "";
vue.nextTick(() => {
var _a, _b;
window.document.title = this.post.title ?? "V2EX";
(_b = (_a = this.$refs) == null ? void 0 : _a.main) == null ? void 0 : _b.focus();
});
} else {
document.body.style.overflow = "unset";
window.document.title = "V2EX";
this.isSticky = false;
this.showRelationReply = false;
if (window.history.state) {
window.history.back();
}
}
}
}
},
mounted() {
setTimeout(() => {
var _a;
this.postDetailWidth = ((_a = this.$refs.mainWrapper) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
});
if (this.isLogin) {
const observer = new IntersectionObserver(
([e2]) => e2.target.toggleAttribute("stuck", e2.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(this.$refs.replyBox);
window.addEventListener("keydown", this.onKeyDown);
}
eventBus.on(CMD.SHOW_CALL, (val) => {
if (val.show) {
this.showCallList = true;
this.replyText = val.text;
if (this.isPost) {
this.callStyle.top = val.top + $(window.win()).scrollTop() + -40 + "px";
} else {
this.callStyle.top = val.top + $(".post-detail").scrollTop() + 15 + "px";
}
this.callStyle.left = val.left - $(".main")[0].getBoundingClientRect().left + 10 + "px";
if (this.selectCallIndex >= this.filterCallList.length) {
this.selectCallIndex = 0;
}
} else {
this.replyText = "";
this.showCallList = false;
this.selectCallIndex = 0;
}
});
eventBus.on(CMD.RELATION_REPLY, (val) => {
this.targetUser = val;
this.showRelationReply = true;
});
eventBus.on(CMD.JUMP, this.jump);
if (this.isPost) {
window.addEventListener("scroll", this.debounceScroll);
}
},
beforeUnmount() {
window.removeEventListener("keydown", this.onKeyDown);
eventBus.off(CMD.SHOW_CALL);
},
methods: {
addTag() {
eventBus.emit(CMD.ADD_TAG, this.post.member.username);
},
removeTag(tag) {
eventBus.emit(CMD.REMOVE_TAG, { username: this.post.member.username, tag });
},
stop(e2) {
},
jump(floor) {
let lastItem = this.replyList[this.replyList.length - 1];
if (floor === "") {
floor = lastItem.floor;
} else {
try {
floor = Number(floor);
} catch (e2) {
floor = lastItem.floor;
}
if (floor === 0) {
floor = 1;
}
if (floor > lastItem.floor)
floor = lastItem.floor;
}
if (!this.post.replyList.length) {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "没有回复可跳转!" });
return;
}
if (floor > this.post.replyList.length) {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
return;
}
let comment = $(`.c_${floor}`);
if (!comment.length) {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
return;
}
comment[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
comment.addClass("ding");
this.currentFloor = floor + 1;
setTimeout(() => {
comment.removeClass("ding");
}, 2e3);
},
collapseTopReplyList() {
$(this.$refs.topReply).slideToggle("fast");
},
goBottom() {
this.isSticky = false;
setTimeout(() => {
if (this.isPost) {
let body = $("body , html");
let scrollHeight = body.prop("scrollHeight");
body.animate({ scrollTop: scrollHeight - 850 }, 300);
} else {
this.$refs.detail.scrollTo({ top: this.$refs.detail.scrollHeight, behavior: "smooth" });
}
});
},
close(from) {
if (this.isPost)
return;
if (from === "space") {
if (this.config.closePostDetailBySpace) {
this.$emit("update:modelValue", false);
}
} else {
this.$emit("update:modelValue", false);
}
},
setCall(e2) {
eventBus.emit(CMD.SET_CALL, e2);
this.showCallList = false;
},
onKeyDown(e2) {
if (!this.modelValue)
return;
if (!this.showCallList)
return;
let length = this.filterCallList.slice(0, 10).length;
if (e2.keyCode === 13) {
this.setCall(this.filterCallList[this.selectCallIndex]);
e2.preventDefault();
}
if (e2.keyCode === 38) {
this.selectCallIndex--;
if (this.selectCallIndex < 0) {
this.selectCallIndex = length - 1;
}
e2.preventDefault();
}
if (e2.keyCode === 40) {
this.selectCallIndex++;
if (this.selectCallIndex > length - 1) {
this.selectCallIndex = 0;
}
e2.preventDefault();
}
},
changeOption(item) {
this.$emit("update:displayType", item);
},
addThank() {
eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "add" });
},
recallThank() {
eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "recall" });
},
scrollTop() {
if (this.isPost) {
$("body , html").animate({ scrollTop: 0 }, 300);
} else {
this.$refs.detail.scrollTo({ top: 0, behavior: "smooth" });
}
}
}
};
const _withScopeId$3 = (n2) => (vue.pushScopeId("data-v-4f952cc2"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$6 = { class: "my-box post-wrapper" };
const _hoisted_2$3 = { class: "header" };
const _hoisted_3$3 = { class: "fr" };
const _hoisted_4$3 = ["href"];
const _hoisted_5$2 = ["src", "alt"];
const _hoisted_6$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("a", { href: "/" }, "V2EX", -1));
const _hoisted_7$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "chevron" }, " › ", -1));
const _hoisted_8$1 = ["href"];
const _hoisted_9$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep10" }, null, -1));
const _hoisted_10 = ["id"];
const _hoisted_11 = ["onclick"];
const _hoisted_12 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-up" }, null, -1));
const _hoisted_13 = ["onclick"];
const _hoisted_14 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-down" }, null, -1));
const _hoisted_15 = [
_hoisted_14
];
const _hoisted_16 = { class: "gray" };
const _hoisted_17 = ["href"];
const _hoisted_18 = ["title"];
const _hoisted_19 = ["href"];
const _hoisted_20 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-info-circle" }, null, -1));
const _hoisted_21 = [
_hoisted_20
];
const _hoisted_22 = ["href"];
const _hoisted_23 = ["href"];
const _hoisted_24 = ["href"];
const _hoisted_25 = { class: "my-tag" };
const _hoisted_26 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
const _hoisted_27 = ["onClick"];
const _hoisted_28 = {
key: 0,
class: "my-box"
};
const _hoisted_29 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "高赞回复", -1));
const _hoisted_30 = { class: "top-reply" };
const _hoisted_31 = { class: "tool" };
const _hoisted_32 = { ref: "topReply" };
const _hoisted_33 = {
key: 1,
class: "my-box my-cell"
};
const _hoisted_34 = ["innerHTML"];
const _hoisted_35 = { class: "my-box comment-wrapper" };
const _hoisted_36 = {
key: 0,
class: "my-cell flex"
};
const _hoisted_37 = { key: 0 };
const _hoisted_38 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("strong", { class: "snow" }, "•", -1));
const _hoisted_39 = ["innerHTML"];
const _hoisted_40 = {
key: 0,
class: "loading-wrapper"
};
const _hoisted_41 = {
key: 1,
class: "comments"
};
const _hoisted_42 = {
key: 2,
id: "no-comments-yet"
};
const _hoisted_43 = { class: "my-cell flex" };
const _hoisted_44 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "添加一条新回复", -1));
const _hoisted_45 = { class: "notice-right gray" };
const _hoisted_46 = { class: "p1" };
const _hoisted_47 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "上下文", -1));
const _hoisted_48 = { class: "top-reply" };
const _hoisted_49 = ["onClick"];
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
const _component_Point = vue.resolveComponent("Point");
const _component_Toolbar = vue.resolveComponent("Toolbar");
const _component_Icon = vue.resolveComponent("Icon");
const _component_Tooltip = vue.resolveComponent("Tooltip");
const _component_Comment = vue.resolveComponent("Comment");
const _component_BaseSelect = vue.resolveComponent("BaseSelect");
const _component_BaseLoading = vue.resolveComponent("BaseLoading");
const _component_PostEditor = vue.resolveComponent("PostEditor");
const _component_SingleComment = vue.resolveComponent("SingleComment");
return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["post-detail", [$options.isNight ? "isNight" : "", $options.pageType, $options.isMobile ? "mobile" : ""]]),
ref: "detail",
onKeydown: _cache[19] || (_cache[19] = vue.withKeys(($event) => $options.close(), ["esc"])),
onScroll: _cache[20] || (_cache[20] = (...args) => _ctx.debounceScroll && _ctx.debounceScroll(...args)),
onClick: _cache[21] || (_cache[21] = ($event) => $options.close("space"))
}, [
vue.createElementVNode("div", {
ref: "main",
class: "main",
tabindex: "1",
onClick: _cache[18] || (_cache[18] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
}, [
vue.createElementVNode("div", {
class: "main-wrapper",
ref: "mainWrapper",
style: vue.normalizeStyle({ width: $options.config.postWidth })
}, [
vue.createElementVNode("div", _hoisted_1$6, [
vue.createElementVNode("div", _hoisted_2$3, [
vue.createElementVNode("div", _hoisted_3$3, [
vue.createElementVNode("a", {
href: `/member/${$options.post.member.username}`,
style: { "width": "73px", "height": "73px", "display": "inline-block" }
}, [
$options.post.member.avatar_large ? (vue.openBlock(), vue.createElementBlock("img", {
key: 0,
src: $options.post.member.avatar_large,
class: "avatar",
style: { "width": "73px", "height": "73px" },
border: "0",
align: "default",
alt: $options.post.member.username
}, null, 8, _hoisted_5$2)) : vue.createCommentVNode("", true)
], 8, _hoisted_4$3)
]),
_hoisted_6$2,
_hoisted_7$1,
vue.createElementVNode("a", {
href: $options.post.node.url
}, vue.toDisplayString($options.post.node.title), 9, _hoisted_8$1),
_hoisted_9$1,
vue.createElementVNode("h1", null, vue.toDisplayString($options.post.title), 1),
!$options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
id: `topic_${$options.post.id}_votes`,
class: "votes"
}, [
vue.createElementVNode("a", {
href: "javascript:",
onclick: `upVoteTopic(${$options.post.id});`,
class: "vote"
}, [
_hoisted_12,
vue.createTextVNode(" ")
], 8, _hoisted_11),
vue.createTextVNode(" "),
vue.createElementVNode("a", {
href: "javascript:",
onclick: `downVoteTopic(${$options.post.id});`,
class: "vote"
}, _hoisted_15, 8, _hoisted_13)
], 8, _hoisted_10)) : vue.createCommentVNode("", true),
vue.createTextVNode(" "),
vue.createElementVNode("small", _hoisted_16, [
vue.createElementVNode("a", {
href: `/member/${$options.post.member.username}`
}, vue.toDisplayString($options.post.member.username), 9, _hoisted_17),
vue.createTextVNode(" · "),
$options.post.member.createDate ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
vue.createElementVNode("span", {
class: vue.normalizeClass($options.post.member.isNew && "danger")
}, vue.toDisplayString($options.post.member.createDate), 3),
vue.createTextVNode(" · ")
], 64)) : vue.createCommentVNode("", true),
$options.post.createDateAgo ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
vue.createElementVNode("span", {
title: $options.post.createDate
}, vue.toDisplayString($options.post.createDateAgo), 9, _hoisted_18),
vue.createTextVNode(" · ")
], 64)) : vue.createCommentVNode("", true),
vue.createTextVNode(" " + vue.toDisplayString($options.post.clickCount) + " 次点击 ", 1),
$options.isMy ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
vue.createTextVNode(" "),
vue.createElementVNode("a", {
href: `/t/${$options.post.id}/info`
}, _hoisted_21, 8, _hoisted_19),
vue.createTextVNode(" "),
$options.canAppend ? (vue.openBlock(), vue.createElementBlock("a", {
key: 0,
href: `/append/topic/${$options.post.id}`,
class: "op"
}, "APPEND", 8, _hoisted_22)) : vue.createCommentVNode("", true),
$options.canEditMove ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
vue.createElementVNode("a", {
href: `/move/topic/${$options.post.id}`,
class: "op"
}, "MOVE", 8, _hoisted_23),
vue.createTextVNode(" "),
vue.createElementVNode("a", {
href: `/edit/topic/${$options.post.id}`,
class: "op"
}, "EDIT", 8, _hoisted_24)
], 64)) : vue.createCommentVNode("", true)
], 64)) : vue.createCommentVNode("", true)
]),
$options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
return vue.openBlock(), vue.createElementBlock("span", _hoisted_25, [
_hoisted_26,
vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
vue.createElementVNode("i", {
class: "fa fa-trash-o remove",
onClick: ($event) => $options.removeTag(i)
}, null, 8, _hoisted_27)
]);
}), 256)),
vue.createElementVNode("span", {
class: "add-tag ago",
onClick: _cache[0] || (_cache[0] = (...args) => $options.addTag && $options.addTag(...args)),
title: "添加标签"
}, "+")
], 64)) : vue.createCommentVNode("", true)
]),
$options.post.headerTemplate ? (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
key: 0,
html: $options.post.headerTemplate
}, null, 8, ["html"])) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
key: 1,
html: $options.post.jsonContent
}, null, 8, ["html"])),
vue.createVNode(_component_Toolbar, {
onReply: _cache[1] || (_cache[1] = ($event) => $data.isSticky = !$data.isSticky)
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_Point, {
onAddThank: $options.addThank,
onRecallThank: $options.recallThank,
item: {
isThanked: $options.post.isThanked,
thankCount: $options.post.thankCount,
username: $options.post.username
},
"api-url": "topic/" + $options.post.id
}, null, 8, ["onAddThank", "onRecallThank", "item", "api-url"])
]),
_: 1
})
]),
$options.topReply.length && $options.config.showTopReply ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_28, [
vue.createElementVNode("div", {
class: "my-cell flex",
onClick: _cache[2] || (_cache[2] = (...args) => $options.collapseTopReplyList && $options.collapseTopReplyList(...args))
}, [
_hoisted_29,
vue.createElementVNode("div", _hoisted_30, [
vue.createVNode(_component_Tooltip, { title: "收起高赞回复" }, {
default: vue.withCtx(() => [
vue.createElementVNode("div", _hoisted_31, [
vue.createVNode(_component_Icon, { icon: "gravity-ui:chevrons-collapse-vertical" })
])
]),
_: 1
})
])
]),
vue.createElementVNode("div", _hoisted_32, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.topReply, (item, index) => {
return vue.openBlock(), vue.createBlock(_component_Comment, {
key: item.floor,
type: "top",
modelValue: $options.topReply[index],
"onUpdate:modelValue": ($event) => $options.topReply[index] = $event
}, null, 8, ["modelValue", "onUpdate:modelValue"]);
}), 128))
], 512)
])) : vue.createCommentVNode("", true),
$options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_33, [
vue.createElementVNode("div", {
class: "inner",
innerHTML: $options.post.fr
}, null, 8, _hoisted_34)
])) : vue.createCommentVNode("", true),
vue.createElementVNode("div", _hoisted_35, [
$options.post.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_36, [
vue.createElementVNode("div", null, [
vue.createTextVNode(vue.toDisplayString($options.post.replyCount) + " 条回复 ", 1),
$options.post.lastReplyDate ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_37, [
vue.createTextVNode(" "),
_hoisted_38,
vue.createTextVNode(" " + vue.toDisplayString($options.post.lastReplyDate), 1)
])) : vue.createCommentVNode("", true)
]),
$options.config.showToolbar ? (vue.openBlock(), vue.createBlock(_component_BaseSelect, {
key: 0,
"display-type": $props.displayType,
"onUpdate:displayType": _cache[3] || (_cache[3] = (e2) => _ctx.$emit("update:displayType", e2))
}, null, 8, ["display-type"])) : (vue.openBlock(), vue.createElementBlock("div", {
key: 1,
class: "fr",
innerHTML: $options.post.fr
}, null, 8, _hoisted_39))
])) : vue.createCommentVNode("", true),
$options.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
$props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_40, [
vue.createVNode(_component_BaseLoading, { size: "large" })
])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_41, [
$props.modelValue ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 0 }, vue.renderList($options.replyList, (item, index) => {
return vue.openBlock(), vue.createBlock(_component_Comment, {
key: item.floor,
modelValue: $options.replyList[index],
"onUpdate:modelValue": ($event) => $options.replyList[index] = $event
}, null, 8, ["modelValue", "onUpdate:modelValue"]);
}), 128)) : vue.createCommentVNode("", true)
]))
], 64)) : vue.createCommentVNode("", true)
]),
!($options.replyList.length || $props.loading) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_42, "目前尚无回复")) : vue.createCommentVNode("", true),
$options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
key: 3,
class: vue.normalizeClass(["my-box", { "sticky": $data.isSticky }]),
ref: "replyBox"
}, [
vue.createElementVNode("div", _hoisted_43, [
_hoisted_44,
vue.createElementVNode("div", _hoisted_45, [
$data.isSticky ? (vue.openBlock(), vue.createElementBlock("a", {
key: 0,
style: { "margin-right": "2rem" },
onClick: _cache[4] || (_cache[4] = ($event) => $data.isSticky = false)
}, "取消回复框停靠")) : vue.createCommentVNode("", true),
vue.createElementVNode("a", {
onClick: _cache[5] || (_cache[5] = (...args) => $options.scrollTop && $options.scrollTop(...args))
}, "回到顶部")
])
]),
vue.createElementVNode("div", _hoisted_46, [
vue.createVNode(_component_PostEditor, {
onClose: $options.goBottom,
ref: "post-editor",
useType: "reply-post",
onClick: _cache[6] || (_cache[6] = ($event) => $data.isSticky = true)
}, null, 8, ["onClose"])
])
], 2)) : vue.createCommentVNode("", true)
], 4),
$data.showRelationReply ? (vue.openBlock(), vue.createElementBlock("div", {
key: 0,
class: "relationReply",
onClick: _cache[10] || (_cache[10] = ($event) => $options.close("space"))
}, [
vue.createElementVNode("div", {
class: "my-cell flex",
onClick: _cache[8] || (_cache[8] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
}, [
_hoisted_47,
vue.createElementVNode("div", _hoisted_48, [
vue.createVNode(_component_Icon, {
icon: "ic:round-close",
onClick: _cache[7] || (_cache[7] = ($event) => $data.showRelationReply = false)
})
])
]),
vue.createElementVNode("div", {
class: "comments",
onClick: _cache[9] || (_cache[9] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
}, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.relationReply, (item, index) => {
return vue.openBlock(), vue.createBlock(_component_SingleComment, {
"is-right": item.username === $data.targetUser.right,
key: item.floor,
comment: item
}, null, 8, ["is-right", "comment"]);
}), 128))
])
])) : vue.createCommentVNode("", true),
$data.showCallList && $options.filterCallList.length ? (vue.openBlock(), vue.createElementBlock("div", {
key: 1,
class: "call-list",
style: vue.normalizeStyle($data.callStyle)
}, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.filterCallList, (item, index) => {
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["call-item", { select: index === $data.selectCallIndex }]),
onClick: ($event) => $options.setCall(item)
}, [
vue.createElementVNode("a", null, vue.toDisplayString(item), 1)
], 10, _hoisted_49);
}), 256))
], 4)) : vue.createCommentVNode("", true),
vue.createElementVNode("div", {
class: "close-btn",
onClick: _cache[11] || (_cache[11] = ($event) => $options.close("btn"))
}, [
vue.createVNode(_component_Icon, { icon: "fontisto:close-a" })
]),
vue.createElementVNode("div", {
class: "scroll-top gray",
onClick: _cache[12] || (_cache[12] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
}, [
vue.createVNode(_component_Icon, { icon: "lucide:move-up" })
]),
vue.createElementVNode("div", {
class: "refresh gray",
onClick: _cache[13] || (_cache[13] = vue.withModifiers(($event) => _ctx.$emit("refresh"), ["stop"]))
}, [
$props.refreshLoading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, { key: 0 })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
key: 1,
icon: "material-symbols:refresh"
}))
]),
vue.createElementVNode("div", {
class: "scroll-to gray",
onClick: _cache[17] || (_cache[17] = vue.withModifiers(($event) => $options.jump($data.currentFloor), ["stop"]))
}, [
vue.createVNode(_component_Icon, { icon: "lucide:move-down" }),
vue.withDirectives(vue.createElementVNode("input", {
type: "text",
"onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.currentFloor = $event),
onClick: _cache[15] || (_cache[15] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"])),
onKeydown: _cache[16] || (_cache[16] = vue.withKeys(($event) => $options.jump($data.currentFloor), ["enter"]))
}, null, 544), [
[vue.vModelText, $data.currentFloor]
])
])
], 512)
], 34)), [
[vue.vShow, $props.modelValue]
]);
}
const PostDetail = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$2], ["__scopeId", "data-v-4f952cc2"]]);
const _hoisted_1$5 = { key: 1 };
const _sfc_main$5 = {
__name: "Base64Tooltip",
setup(__props) {
const tooltip = vue.ref(null);
const show = vue.ref(false);
const originalText = vue.ref("");
const decodeText = vue.ref("");
const styleObject = vue.reactive({
left: "-100vw",
top: "-100vh"
});
vue.onMounted(() => {
eventBus.on(CMD.SHOW_TOOLTIP, ({ text, e: e2 }) => {
setTimeout(() => show.value = true);
originalText.value = text;
decodeText.value = "";
styleObject.left = e2.clientX + "px";
styleObject.top = e2.clientY + 20 + "px";
});
window.addEventListener("click", (e2) => {
if (!tooltip.value)
return;
if (!tooltip.value.contains(e2.target) && show.value) {
show.value = false;
}
}, { capture: true });
const fn = () => show.value && (show.value = false);
$(".post-detail", window.win().doc).on("scroll", fn);
});
function copy() {
if (window.win().navigator.clipboard) {
window.win().navigator.clipboard.writeText(decodeText.value);
eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "复制成功" });
} else {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "复制失败!浏览器不支持!" });
}
}
function base64ToArrayBuffer(base64) {
let binary_string = window.atob(base64);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
function decode() {
try {
new Blob([base64ToArrayBuffer(originalText.value)]).text().then((r2) => {
decodeText.value = r2;
});
} catch (e2) {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "Base64解码失败!不是标准数据!" });
}
}
return (_ctx, _cache) => {
return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
class: "base64_tooltip",
style: vue.normalizeStyle(styleObject),
onClick: decode,
ref_key: "tooltip",
ref: tooltip
}, [
!decodeText.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
vue.createTextVNode(" Base64解码:" + vue.toDisplayString(originalText.value) + " ", 1),
vue.createVNode(vue.unref(Icon), { icon: "system-uicons:translate" })
], 64)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$5, [
vue.createElementVNode("span", null, vue.toDisplayString(decodeText.value), 1),
vue.createVNode(BaseButton, {
class: "btn",
size: "small",
onClick: copy
}, {
default: vue.withCtx(() => [
vue.createTextVNode("点击复制")
]),
_: 1
})
]))
], 4)), [
[vue.vShow, show.value]
]);
};
}
};
const Base64Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-c50fb66c"]]);
const _sfc_main$4 = {
name: "Msg",
components: { Icon },
props: {
type: "",
text: ""
},
created() {
setTimeout(() => {
this.$emit("close");
}, 3e3);
}
};
const _hoisted_1$4 = { class: "right" };
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
const _component_Icon = vue.resolveComponent("Icon");
return vue.openBlock(), vue.createElementBlock("div", {
class: vue.normalizeClass(["msg", $props.type])
}, [
vue.createElementVNode("div", {
class: "left",
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
}, [
vue.createVNode(_component_Icon, { icon: "ic:round-close" })
]),
vue.createElementVNode("div", _hoisted_1$4, vue.toDisplayString($props.text), 1)
], 2);
}
const Msg = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$1], ["__scopeId", "data-v-8bf692ea"]]);
const _withScopeId$2 = (n2) => (vue.pushScopeId("data-v-674b86aa"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$3 = {
key: 0,
class: "tag-modal modal"
};
const _hoisted_2$2 = { class: "wrapper" };
const _hoisted_3$2 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 添加标签 ", -1));
const _hoisted_4$2 = { class: "option" };
const _hoisted_5$1 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户:", -1));
const _hoisted_6$1 = { class: "btns" };
const _sfc_main$3 = {
__name: "TagModal",
props: ["tags"],
emits: ["update:tags"],
setup(__props, { emit: __emit }) {
const tagModal = vue.reactive({
show: false,
currentUsername: "",
tag: ""
});
const props = __props;
const emit = __emit;
const inputRef = vue.ref();
vue.onMounted(() => {
eventBus.on(CMD.ADD_TAG, (username) => {
tagModal.currentUsername = username;
tagModal.show = true;
vue.nextTick(() => {
inputRef.value.focus();
});
});
});
async function addTag() {
if (!tagModal.tag) {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请输入标签" });
return;
}
let oldTag = window.clone(props.tags);
let tempTag = window.clone(props.tags);
let userTags = tempTag[tagModal.currentUsername] ?? [];
let rIndex = userTags.findIndex((v) => v === tagModal.tag);
if (rIndex > -1) {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "标签已存在!" });
return;
} else {
userTags.push(tagModal.tag);
}
tempTag[tagModal.currentUsername] = userTags;
emit("update:tags", tempTag);
tagModal.tag = "";
tagModal.show = false;
let res = await window.parse.saveTags(tempTag);
if (!res) {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签添加失败!" });
emit("update:tags", oldTag);
}
}
return (_ctx, _cache) => {
return vue.openBlock(), vue.createBlock(vue.Transition, null, {
default: vue.withCtx(() => [
tagModal.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
vue.createElementVNode("div", {
class: "mask",
onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => tagModal.show = false, ["stop"]))
}),
vue.createElementVNode("div", _hoisted_2$2, [
_hoisted_3$2,
vue.createElementVNode("div", _hoisted_4$2, [
_hoisted_5$1,
vue.createElementVNode("div", null, [
vue.createElementVNode("b", null, vue.toDisplayString(tagModal.currentUsername), 1)
])
]),
vue.withDirectives(vue.createElementVNode("input", {
type: "text",
ref_key: "inputRef",
ref: inputRef,
style: { "width": "100%" },
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tagModal.tag = $event),
onKeydown: vue.withKeys(addTag, ["enter"])
}, null, 544), [
[vue.vModelText, tagModal.tag]
]),
vue.createElementVNode("div", _hoisted_6$1, [
vue.createVNode(BaseButton, {
type: "link",
onClick: _cache[2] || (_cache[2] = ($event) => tagModal.show = false)
}, {
default: vue.withCtx(() => [
vue.createTextVNode("取消")
]),
_: 1
}),
vue.createVNode(BaseButton, { onClick: addTag }, {
default: vue.withCtx(() => [
vue.createTextVNode("确定")
]),
_: 1
})
])
])
])) : vue.createCommentVNode("", true)
]),
_: 1
});
};
}
};
const TagModal = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-674b86aa"]]);
const _hoisted_1$2 = { class: "msgs" };
const _sfc_main$2 = {
__name: "MsgModal",
setup(__props) {
const msgList = vue.reactive([
// {type: 'success', text: '123', id: Date.now()}
]);
vue.onMounted(() => {
eventBus.on(CMD.SHOW_MSG, (val) => {
msgList.push({ ...val, id: Date.now() });
});
});
function removeMsg(id) {
let rIndex = msgList.findIndex((item) => item.id === id);
if (rIndex > -1) {
msgList.splice(rIndex, 1);
}
}
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(msgList, (v) => {
return vue.openBlock(), vue.createBlock(Msg, {
key: v.id,
type: v.type,
text: v.text,
onClose: ($event) => removeMsg(v.id)
}, null, 8, ["type", "text", "onClose"]);
}), 128))
]);
};
}
};
const MsgModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b73f4332"]]);
let u = ".__cf_email__", f = "data-cfemail", d = document.createElement("div");
function e(e2) {
console.error(e2);
}
function r(e2, t) {
let r2 = e2.substr(t, 2);
return parseInt(r2, 16);
}
function n(href, index) {
let o = "", a = r(href, index);
for (let i = index + 2; i < href.length; i += 2) {
let l = r(href, i) ^ a;
o += String.fromCharCode(l);
}
try {
o = decodeURIComponent(escape(o));
} catch (u2) {
e(u2);
}
d.innerHTML = '';
return d.childNodes[0].getAttribute("href") || "";
}
function decodeEmail(body) {
try {
let as = body.find(u);
as.each(function() {
try {
let o = this, a = o.parentNode, i = o.getAttribute(f);
if (i) {
let l = n(i, 0), d2 = document.createTextNode(l);
a.replaceChild(d2, o);
}
} catch (h2) {
e(h2);
}
});
} catch (s) {
e(s);
}
}
const _withScopeId$1 = (n2) => (vue.pushScopeId("data-v-882b932b"), n2 = n2(), vue.popScopeId(), n2);
const _hoisted_1$1 = {
key: 0,
class: "tag-modal modal"
};
const _hoisted_2$1 = { class: "modal-root" };
const _hoisted_3$1 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 提醒系统 ", -1));
const _hoisted_4$1 = ["innerHTML"];
const _sfc_main$1 = {
__name: "NotificationModal",
props: ["modelValue", "h"],
emits: ["update:modelValue"],
setup(__props, { emit: __emit }) {
const emit = __emit;
vue.onMounted(() => {
});
function close() {
emit("update:modelValue", false);
}
return (_ctx, _cache) => {
return vue.openBlock(), vue.createBlock(vue.Transition, null, {
default: vue.withCtx(() => [
__props.modelValue ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
vue.createElementVNode("div", {
class: "mask",
onClick: vue.withModifiers(close, ["stop"])
}),
vue.createElementVNode("div", _hoisted_2$1, [
vue.createElementVNode("div", { class: "modal-header" }, [
_hoisted_3$1,
vue.createElementVNode("i", {
class: "fa fa-times",
onClick: close
})
]),
vue.createElementVNode("div", {
innerHTML: __props.h,
class: "modal-body"
}, null, 8, _hoisted_4$1)
])
])) : vue.createCommentVNode("", true)
]),
_: 1
});
};
}
};
const NotificationModal = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-882b932b"]]);
const _sfc_main = {
components: {
BaseButton,
NotificationModal,
BaseLoading,
BaseSwitch,
MsgModal,
TagModal,
Tooltip,
Setting,
PostDetail,
Base64Tooltip,
Msg
},
provide() {
return {
isMobile: vue.computed(() => window.vals.isMobile),
isLogin: vue.computed(() => this.isLogin),
isNight: vue.computed(() => this.isNight),
pageType: vue.computed(() => this.pageType),
tags: vue.computed(() => this.tags),
show: vue.computed(() => this.show),
post: vue.computed(() => this.current),
config: vue.computed(() => this.config),
allReplyUsers: vue.computed(() => {
var _a, _b, _c;
if ((_a = this.current) == null ? void 0 : _a.replyList) {
return Array.from(new Set(((_c = (_b = this.current) == null ? void 0 : _b.replyList) == null ? void 0 : _c.map((v) => v.username)) ?? []));
}
return [];
}),
showConfig: this.showConfig
};
},
data() {
return {
loading: window.pageType === PageType.Post,
refreshLoading: false,
loadMore: false,
isLogin: !!window.user.username,
pageType: window.pageType,
isNight: window.isNight,
stopMe: window.stopMe,
//停止使用脚本
show: false,
current: window.clone(window.initPost),
list: [],
config: window.clone(window.config),
tags: window.user.tags,
configModal: {
show: false
},
notificationModal: {
show: false,
h: ""
}
};
},
computed: {
targetUserTags() {
return this.tags[window.targetUserName] ?? [];
},
isList() {
return [PageType.Home, PageType.Node].includes(this.pageType);
},
isPost() {
return this.pageType === PageType.Post;
},
isMember() {
return this.pageType === PageType.Member;
}
},
watch: {
config: {
handler(newVal) {
let config2 = { [window.user.username ?? "default"]: newVal };
localStorage.setItem("v2ex-config", JSON.stringify(config2));
window.config = newVal;
},
deep: true
},
tags(newVal) {
window.user.tags = newVal;
},
"config.viewType"(newVal) {
if (!newVal)
return;
if (newVal === "card") {
$(".post-item").each(function() {
$(this).addClass("preview");
});
} else {
$(".post-item").each(function() {
$(this).removeClass("preview");
});
}
}
},
created() {
let that = this;
this.initEvent();
window.cb = this.winCb;
if (!window.canParseV2exPage)
return;
$(document).on("click", "a", this.clickA);
$(document).on("click", ".post-item", function(e2) {
if (e2.currentTarget.getAttribute("script"))
return;
if (that.stopMe)
return true;
if (this.classList.contains("preview")) {
if (e2.target.tagName !== "A" && e2.target.tagName !== "IMG" && !e2.target.classList.contains("toggle")) {
console.log("点空白处", this);
let id = this.dataset["id"];
let href = this.dataset["href"];
if (id) {
that.clickPost(e2, id, href);
} else {
if (href)
location.href = href;
}
}
}
});
$(document).on("click", ".toggle", (e2) => {
if (this.stopMe)
return true;
let id = e2.target.dataset["id"];
let itemDom = document.querySelector(`.id_${id}`);
if (itemDom.classList.contains("preview")) {
e2.target.innerText = "预览";
itemDom.classList.remove("preview");
} else {
if (this.config.viewType !== "card") {
let index = this.list.findIndex((v) => v.id == id);
if (index > -1) {
e2.target.innerText = "收起";
itemDom.classList.add("preview");
} else {
e2.target.innerText = "加载中";
functions.getPostDetailByApi(id).then((res) => {
if (res.content_rendered) {
res.href = itemDom.dataset["href"];
this.list.push(getDefaultPost(res));
itemDom.classList.add("preview");
e2.target.innerText = "收起";
functions.appendPostContent(res, itemDom);
} else {
e2.target.innerText = "预览";
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "主题暂无正文!" });
}
});
}
} else {
e2.target.innerText = "收起";
itemDom.classList.add("preview");
}
}
});
window.onpopstate = (event) => {
if (event.state) {
if (!this.show)
this.show = true;
} else {
if (this.show)
this.show = false;
}
};
window.deleteNotification = (nId, token) => {
console.log("deleteNotification", nId, token);
let item = $("#n_" + nId);
item.slideUp("fast");
$.post({
url: "/delete/notification/" + nId + "?once=" + token,
success() {
$.get({
url: "/notifications/below/" + window.notificationBottom,
success(data, status, request) {
item.remove();
$("#notifications").append(data);
window.notificationBottom = request.getResponseHeader("X-V2EX-New-Notification-Bottom");
},
error() {
item.slideDown("fast");
}
});
},
error() {
item.slideDown("fast");
}
});
};
},
beforeUnmount() {
eventBus.clear();
$(document).off("click", "a", this.clickA);
},
methods: {
async getUnreadMessagesCount() {
var _a, _b;
const res = await fetch(`${location.origin}/mission`);
const htmlText = await res.text();
const $page = $(htmlText);
const text = $page.find('#Rightbar a[href^="/notifications"]').text();
if (text.includes("未读提醒")) {
const countStr = (_a = text.match(/\d+/)) == null ? void 0 : _a.at(0);
if (countStr) {
return Number((_b = text.match(/\d+/)) == null ? void 0 : _b.at(0));
}
} else {
return 0;
}
throw new Error("无法获取未读消息数量");
},
clickA(e2) {
let that = this;
if (e2.currentTarget.getAttribute("script"))
return;
if (that.stopMe)
return true;
let { href, id, title } = functions.parseA(e2.currentTarget);
if (href.includes("/settings/night/toggle"))
return;
if (href.includes("/?tab="))
return;
if (href.includes("/go"))
return;
if (href === window.origin + "/#;")
return;
if (href === window.origin + "/")
return;
if (href.includes("/notifications"))
;
if (id) {
that.clickPost(e2, id, href, title);
} else {
if (that.config.newTabOpen) {
that.stopEvent(e2);
functions.openNewTab(href, that.config.newTabOpenActive);
}
}
},
stopEvent(e2) {
e2.preventDefault();
e2.stopPropagation();
},
async clickPost(e2, id, href, title = "") {
if (id) {
if (this.config.clickPostItemOpenDetail) {
this.stopEvent(e2);
let postItem = getDefaultPost();
let index = this.list.findIndex((v) => v.id == id);
if (index > -1) {
postItem = this.list[index];
}
if (!postItem.title)
postItem.title = title ?? "加载中";
postItem.id = id;
postItem.href = href;
this.getPostDetail(postItem);
return;
}
if (this.config.newTabOpen) {
this.stopEvent(e2);
functions.openNewTab(`https://www.v2ex.com/t/${id}?p=1`, this.config.newTabOpenActive);
}
}
},
showPost() {
this.show = true;
$(`#Wrapper #Main .box:lt(3)`).each(function() {
$(this).hide();
});
},
showConfig() {
this.configModal.show = true;
},
async winCb({ type, value }) {
console.log("回调的类型", type, value);
if (type === "openSetting") {
this.showConfig();
}
if (type === "syncData") {
this.list = Object.assign(this.list, window.postList);
this.config = window.config;
this.stopMe = window.stopMe;
this.tags = window.user.tags;
}
if (type === "warningNotice") {
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: value });
}
if (this.stopMe)
return;
if (type === "restorePost") {
this.show = false;
this.loading = false;
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "脚本无法查看此页面!" });
$(`#Wrapper #Main .box:lt(3)`).each(function() {
$(this).show();
});
}
if (type === "postContent") {
this.current = Object.assign(this.current, value);
this.current.inList = true;
if (this.config.autoOpenDetail) {
this.showPost();
}
}
if (type === "postReplies") {
this.current = Object.assign(this.current, value);
this.list.push(this.clone(this.current));
this.loading = false;
}
},
clone(val) {
return window.clone(val);
},
regenerateReplyList() {
if (this.current.replyList.length) {
this.current.replyCount = this.current.replyList.length;
let res = functions.createNestedList(this.current.replyList);
if (res) {
this.current.nestedReplies = res;
}
let dup_res = functions.createNestedRedundantList(this.current.replyList);
if (dup_res) {
this.current.nestedRedundReplies = dup_res;
}
} else {
this.current.replyCount = 0;
this.current.nestedReplies = [];
this.current.nestedRedundReplies = [];
}
if (this.list.length) {
let rIndex = this.list.findIndex((i) => i.id === this.current.id);
if (rIndex > -1) {
this.list[rIndex] = this.clone(this.current);
}
}
},
initEvent() {
eventBus.on(CMD.CHANGE_COMMENT_THANK, (val) => {
console.log("CHANGE_COMMENT_THANK", val);
const { id, type } = val;
let currentI = this.current.replyList.findIndex((i) => i.id === id);
if (currentI > -1) {
this.current.replyList[currentI].isThanked = type === "add";
if (type === "add") {
this.current.replyList[currentI].thankCount++;
} else {
this.current.replyList[currentI].thankCount--;
}
this.regenerateReplyList();
}
});
eventBus.on(CMD.CHANGE_POST_THANK, (val) => {
const { id, type } = val;
this.current.isThanked = type === "add";
if (type === "add") {
this.current.thankCount++;
} else {
this.current.thankCount--;
}
let currentI = this.list.findIndex((i) => i.id === id);
if (currentI > -1) {
this.list[currentI].isThanked = type === "add";
if (type === "add") {
this.list[currentI].thankCount++;
} else {
this.list[currentI].thankCount++;
}
}
});
eventBus.on(CMD.REMOVE, (val) => {
let removeIndex = this.current.replyList.findIndex((i) => i.floor === val);
if (removeIndex > -1) {
this.current.replyList.splice(removeIndex, 1);
}
this.regenerateReplyList();
});
eventBus.on(CMD.IGNORE, () => {
this.show = false;
let rIndex = this.list.findIndex((i) => i.id === this.current.id);
if (rIndex > -1) {
this.list.splice(rIndex, 1);
}
this.current = this.clone(window.initPost);
});
eventBus.on(CMD.MERGE, (val) => {
this.current = Object.assign(this.current, val);
let rIndex = this.list.findIndex((i) => i.id === this.current.id);
if (rIndex > -1) {
this.list[rIndex] = this.clone(this.current);
}
});
eventBus.on(CMD.ADD_REPLY, (item) => {
this.current.replyList.push(item);
this.regenerateReplyList();
});
eventBus.on(CMD.REFRESH_ONCE, async (once) => {
if (once) {
if (typeof once === "string") {
let res = once.match(/var once = "([\d]+)";/);
if (res && res[1]) {
this.current.once = Number(res[1]);
return;
}
}
if (typeof once === "number") {
this.current.once = once;
return;
}
}
window.fetchOnce().then((r2) => {
this.current.once = r2;
});
});
eventBus.on(CMD.REMOVE_TAG, async ({ username, tag }) => {
let oldTag = this.clone(this.tags);
let tags = this.tags[username] ?? [];
let rIndex = tags.findIndex((v) => v === tag);
if (rIndex > -1) {
tags.splice(rIndex, 1);
}
this.tags[username] = tags;
let res = await window.parse.saveTags(this.tags);
if (!res) {
eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签删除失败!" });
this.tags = oldTag;
}
});
eventBus.on(CMD.REFRESH_POST, () => this.getPostDetail(this.current));
},
async getPostDetail(post) {
this.current = post;
this.show = true;
let url = window.baseUrl + "/t/" + this.current.id;
this.current.url = url;
let alreadyHasReply = this.current.replyList.length;
if (alreadyHasReply) {
this.refreshLoading = true;
} else {
this.loading = true;
functions.getPostDetailByApi(this.current.id).then((d2) => {
d2.replyCount = d2.replies;
this.current = Object.assign(this.current, d2);
if (this.current.replyCount > MAX_REPLY_LIMIT) {
functions.openNewTab(`${location.origin}/t/${this.current.id}?p=1&script=1`, true);
eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "由于回复数量较多,已为您单独打开此主题" });
this.loading = this.show = false;
return;
} else {
this.current.jsonContent = `