V2Next

V2Next - 一个好用的V2EX脚本,已适配移动端!

当前为 2024-01-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name V2Next
  3. // @namespace http://tampermonkey.net/
  4. // @version 7.9.9
  5. // @author zyronon
  6. // @description V2Next - 一个好用的V2EX脚本,已适配移动端!
  7. // @license GPL License
  8. // @icon https://v2next.netlify.app/favicon.ico
  9. // @homepage https://github.com/zyronon/web-scripts
  10. // @homepageURL https://github.com/zyronon/web-scripts
  11. // @supportURL https://update.greasyfork.org/scripts/458024/V2Next.user.js
  12. // @match https://v2ex.com/
  13. // @match https://v2ex.com/?tab=*
  14. // @match https://v2ex.com/t/*
  15. // @match https://v2ex.com/recent*
  16. // @match https://v2ex.com/go/*
  17. // @match https://v2ex.com/member/*
  18. // @match https://*.v2ex.com/
  19. // @match https://*.v2ex.com/?tab=*
  20. // @match https://*.v2ex.com/t/*
  21. // @match https://*.v2ex.com/recent*
  22. // @match https://*.v2ex.com/go/*
  23. // @match https://*.v2ex.com/member/*
  24. // @require https://cdn.jsdelivr.net/npm/vue@3.4.14/dist/vue.global.prod.js
  25. // @grant GM_addStyle
  26. // @grant GM_notification
  27. // @grant GM_openInTab
  28. // @grant GM_registerMenuCommand
  29. // ==/UserScript==
  30.  
  31.  
  32. (function (vue) {
  33. 'use strict';
  34.  
  35. var PageType = /* @__PURE__ */ ((PageType2) => {
  36. PageType2["Home"] = "Home";
  37. PageType2["Node"] = "Node";
  38. PageType2["Post"] = "Post";
  39. PageType2["Member"] = "Member";
  40. PageType2["Changes"] = "Changes";
  41. return PageType2;
  42. })(PageType || {});
  43. var CommentDisplayType = /* @__PURE__ */ ((CommentDisplayType2) => {
  44. CommentDisplayType2[CommentDisplayType2["FloorInFloor"] = 0] = "FloorInFloor";
  45. CommentDisplayType2[CommentDisplayType2["FloorInFloorNoCallUser"] = 4] = "FloorInFloorNoCallUser";
  46. CommentDisplayType2[CommentDisplayType2["FloorInFloorNested"] = 5] = "FloorInFloorNested";
  47. CommentDisplayType2[CommentDisplayType2["Like"] = 1] = "Like";
  48. CommentDisplayType2[CommentDisplayType2["V2exOrigin"] = 2] = "V2exOrigin";
  49. CommentDisplayType2[CommentDisplayType2["OnlyOp"] = 3] = "OnlyOp";
  50. CommentDisplayType2[CommentDisplayType2["New"] = 6] = "New";
  51. return CommentDisplayType2;
  52. })(CommentDisplayType || {});
  53. const MAX_REPLY_LIMIT = 400;
  54. const _sfc_main$j = {
  55. name: "Tooltip",
  56. props: {
  57. title: {
  58. type: String,
  59. default() {
  60. return "";
  61. }
  62. },
  63. disabled: {
  64. type: Boolean,
  65. default() {
  66. return false;
  67. }
  68. }
  69. },
  70. data() {
  71. return {
  72. show: false
  73. };
  74. },
  75. methods: {
  76. showPop(e2) {
  77. if (this.disabled)
  78. return;
  79. if (!this.title)
  80. return;
  81. e2.stopPropagation();
  82. let rect = e2.target.getBoundingClientRect();
  83. this.show = true;
  84. vue.nextTick(() => {
  85. var _a, _b;
  86. let tip = (_b = (_a = this.$refs) == null ? void 0 : _a.tip) == null ? void 0 : _b.getBoundingClientRect();
  87. if (!tip)
  88. return;
  89. if (rect.top < 50) {
  90. this.$refs.tip.style.top = rect.top + rect.height + 10 + "px";
  91. } else {
  92. this.$refs.tip.style.top = rect.top - tip.height - 10 + "px";
  93. }
  94. let tipWidth = tip.width;
  95. let rectWidth = rect.width;
  96. this.$refs.tip.style.left = rect.left - (tipWidth - rectWidth) / 2 + "px";
  97. });
  98. }
  99. },
  100. render() {
  101. let Vnode = this.$slots.default()[0];
  102. return vue.createVNode(vue.Fragment, null, [this.show && this.title && vue.createVNode(vue.Teleport, {
  103. "to": "body"
  104. }, {
  105. default: () => [vue.createVNode(vue.Transition, {
  106. "name": "fade"
  107. }, {
  108. default: () => [vue.createVNode("div", {
  109. "ref": "tip",
  110. "className": "tip"
  111. }, [this.title])]
  112. })]
  113. }), vue.createVNode(Vnode, {
  114. "onClick": () => this.show = false,
  115. "onmouseenter": (e2) => this.showPop(e2),
  116. "onmouseleave": () => this.show = false
  117. }, null)]);
  118. }
  119. };
  120. const _export_sfc = (sfc, props) => {
  121. const target = sfc.__vccOpts || sfc;
  122. for (const [key, val] of props) {
  123. target[key] = val;
  124. }
  125. return target;
  126. };
  127. const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-ee672411"]]);
  128. const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
  129. __name: "BaseSwitch",
  130. props: {
  131. modelValue: { type: Boolean }
  132. },
  133. emits: ["update:modelValue"],
  134. setup(__props, { emit: __emit }) {
  135. return (_ctx, _cache) => {
  136. return vue.openBlock(), vue.createElementBlock("div", {
  137. class: vue.normalizeClass(["switch", { active: _ctx.modelValue }]),
  138. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", !_ctx.modelValue))
  139. }, null, 2);
  140. };
  141. }
  142. });
  143. const BaseSwitch = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-e7c0fbef"]]);
  144. const _sfc_main$h = {
  145. name: "Setting",
  146. components: {
  147. BaseSwitch,
  148. Tooltip
  149. },
  150. inject: ["isNight"],
  151. props: {
  152. modelValue: {
  153. type: Object,
  154. default() {
  155. return {};
  156. }
  157. },
  158. show: {
  159. type: Boolean,
  160. default() {
  161. return false;
  162. }
  163. }
  164. },
  165. data() {
  166. return {
  167. tabIndex: 0,
  168. config: window.clone(this.modelValue)
  169. };
  170. },
  171. computed: {
  172. windowConst() {
  173. return window.const;
  174. },
  175. CommentDisplayType() {
  176. return CommentDisplayType;
  177. },
  178. isNew() {
  179. return this.config.version < window.currentVersion;
  180. }
  181. },
  182. watch: {
  183. config: {
  184. handler(n2) {
  185. n2.topReplyLoveMinCount = Math.trunc(n2.topReplyLoveMinCount);
  186. if (n2.topReplyLoveMinCount < 0) {
  187. n2.topReplyLoveMinCount = 1;
  188. }
  189. this.$emit("update:modelValue", n2);
  190. },
  191. deep: true
  192. }
  193. },
  194. methods: {
  195. close() {
  196. this.config.version = window.currentVersion;
  197. this.$emit("update:show", false);
  198. }
  199. }
  200. };
  201. const _withScopeId$b = (n2) => (vue.pushScopeId("data-v-0c0fac4f"), n2 = n2(), vue.popScopeId(), n2);
  202. const _hoisted_1$g = {
  203. key: 0,
  204. class: "setting-modal modal"
  205. };
  206. const _hoisted_2$f = { class: "modal-root" };
  207. const _hoisted_3$b = { class: "modal-header" };
  208. const _hoisted_4$b = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 脚本设置 ", -1));
  209. const _hoisted_5$8 = { class: "body" };
  210. const _hoisted_6$8 = { class: "left" };
  211. const _hoisted_7$7 = { class: "tabs" };
  212. const _hoisted_8$7 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("span", null, "列表设置", -1));
  213. const _hoisted_9$7 = [
  214. _hoisted_8$7
  215. ];
  216. const _hoisted_10$6 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("span", null, "帖子设置", -1));
  217. const _hoisted_11$6 = [
  218. _hoisted_10$6
  219. ];
  220. const _hoisted_12$6 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("span", null, "其他设置", -1));
  221. const _hoisted_13$6 = [
  222. _hoisted_12$6
  223. ];
  224. const _hoisted_14$6 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("span", null, "关于脚本", -1));
  225. const _hoisted_15$6 = [
  226. _hoisted_14$6
  227. ];
  228. const _hoisted_16$6 = { class: "modal-content" };
  229. const _hoisted_17$5 = { class: "scroll" };
  230. const _hoisted_18$5 = { key: 0 };
  231. const _hoisted_19$4 = { class: "row" };
  232. const _hoisted_20$4 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "列表展示方式", -1));
  233. const _hoisted_21$4 = { class: "wrapper" };
  234. const _hoisted_22$3 = { class: "radio-group2" };
  235. const _hoisted_23$3 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  236. const _hoisted_24$2 = { class: "row" };
  237. const _hoisted_25$3 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "列表hover时显示预览按钮", -1));
  238. const _hoisted_26$2 = { class: "wrapper" };
  239. const _hoisted_27$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  240. const _hoisted_28$1 = { class: "row" };
  241. const _hoisted_29$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "帖子弹框显示", -1));
  242. const _hoisted_30$1 = { class: "wrapper" };
  243. const _hoisted_31$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 开启此选项后,帖子始终会以弹框的方式显示。优先级大于“新标签页打开链接” ", -1));
  244. const _hoisted_32$1 = { class: "row" };
  245. const _hoisted_33$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "新标签页打开链接", -1));
  246. const _hoisted_34$1 = { class: "wrapper" };
  247. const _hoisted_35$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 网页上所有链接通过新标签页打开 ", -1));
  248. const _hoisted_36$1 = { key: 1 };
  249. const _hoisted_37$1 = { class: "row" };
  250. const _hoisted_38$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "显示回复展示方式", -1));
  251. const _hoisted_39$1 = { class: "wrapper" };
  252. const _hoisted_40$1 = { class: "row" };
  253. const _hoisted_41$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "回复展示方式", -1));
  254. const _hoisted_42$1 = { class: "wrapper" };
  255. const _hoisted_43$1 = { class: "radio-group2" };
  256. const _hoisted_44$1 = { class: "row" };
  257. const _hoisted_45$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "单独打开帖子时默认显示楼中楼", -1));
  258. const _hoisted_46$1 = { class: "wrapper" };
  259. const _hoisted_47$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 单独打开这种地址 https://v2ex.com/t/xxxx 时,是否默认显示楼中楼 ", -1));
  260. const _hoisted_48$1 = { class: "row" };
  261. const _hoisted_49$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "点击左右两侧透明处关闭帖子详情弹框", -1));
  262. const _hoisted_50$1 = { class: "wrapper" };
  263. const _hoisted_51$1 = { class: "row" };
  264. const _hoisted_52$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "正文超长自动折叠", -1));
  265. const _hoisted_53$1 = { class: "wrapper" };
  266. const _hoisted_54$1 = { class: "row" };
  267. const _hoisted_55$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "帖子宽度", -1));
  268. const _hoisted_56$1 = { class: "wrapper" };
  269. const _hoisted_57$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  270. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则默认宽度为77rem。接受合法的width值: "),
  271. /* @__PURE__ */ vue.createElementVNode("a", {
  272. href: "https://vue3js.cn/interview/css/em_px_rem_vh_vw.html#%E4%BA%8C%E3%80%81%E5%8D%95%E4%BD%8D",
  273. target: "_blank"
  274. }, "rem、px、vw、vh(点此查看)"),
  275. /* @__PURE__ */ vue.createTextVNode("。 vw代表屏幕百分比,如想要屏幕的66%,请填写66vw ")
  276. ], -1));
  277. const _hoisted_58$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 提示:此项设置以后,单独打开详情页时会出现帖子突然变宽(窄)的问题,暂时无解 ", -1));
  278. const _hoisted_59$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  279. const _hoisted_60$1 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  280. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "高赞回复")
  281. ], -1));
  282. const _hoisted_61$1 = { class: "row" };
  283. const _hoisted_62 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "显示高赞回复", -1));
  284. const _hoisted_63 = { class: "wrapper" };
  285. const _hoisted_64 = { class: "row" };
  286. const _hoisted_65 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "最多显示多少个高赞回复", -1));
  287. const _hoisted_66 = { class: "wrapper" };
  288. const _hoisted_67 = { class: "row" };
  289. const _hoisted_68 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "最少需要多少赞才能被判定为高赞", -1));
  290. const _hoisted_69 = { class: "wrapper" };
  291. const _hoisted_70 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  292. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "记忆阅读")
  293. ], -1));
  294. const _hoisted_71 = { class: "row" };
  295. const _hoisted_72 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "记录上次阅读楼层(误差1层左右):", -1));
  296. const _hoisted_73 = { class: "wrapper" };
  297. const _hoisted_74 = { class: "row" };
  298. const _hoisted_75 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "打开帖子自动跳转到上次阅读楼层", -1));
  299. const _hoisted_76 = { class: "wrapper" };
  300. const _hoisted_77 = { key: 2 };
  301. const _hoisted_78 = { class: "row" };
  302. const _hoisted_79 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "用户打标签(跨平台,数据保存在自己的记事本):", -1));
  303. const _hoisted_80 = { class: "wrapper" };
  304. const _hoisted_81 = { class: "row" };
  305. const _hoisted_82 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "划词显示Base64解码框", -1));
  306. const _hoisted_83 = { class: "wrapper" };
  307. const _hoisted_84 = { class: "row" };
  308. const _hoisted_85 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自动签到", -1));
  309. const _hoisted_86 = { class: "wrapper" };
  310. const _hoisted_87 = { class: "row" };
  311. const _hoisted_88 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自定义背景", -1));
  312. const _hoisted_89 = { class: "wrapper" };
  313. const _hoisted_90 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  314. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则背景颜色默认为 #e2e2e2。接受一个合法的css color值:例如"),
  315. /* @__PURE__ */ vue.createElementVNode("a", {
  316. href: "https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value",
  317. target: "_blank"
  318. }, "red、#ffffff、rgb(222,222,22)(点此查看)"),
  319. /* @__PURE__ */ vue.createTextVNode("等等。 ")
  320. ], -1));
  321. const _hoisted_91 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  322. const _hoisted_92 = { class: "row" };
  323. const _hoisted_93 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "收藏时提醒添加到书签", -1));
  324. const _hoisted_94 = { class: "wrapper" };
  325. const _hoisted_95 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " V站帐号一旦被封禁,则无法登录,无法查看账号收藏了 ", -1));
  326. const _hoisted_96 = { key: 3 };
  327. const _hoisted_97 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h1", null, "V2EX Next", -1));
  328. const _hoisted_98 = { class: "project-desc" };
  329. const _hoisted_99 = ["href"];
  330. const _hoisted_100 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("b", null, "请帮我点一个Star,您的Star是对我最大的鼓励", -1));
  331. const _hoisted_101 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h2", null, "为什么选择这个,而不是其他?", -1));
  332. const _hoisted_102 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h3", null, "其他脚本:", -1));
  333. const _hoisted_103 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h3", null, "本脚本:", -1));
  334. const _hoisted_104 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("b", null, "最好用的楼中楼、查看回复上下文、高赞回复、简洁模式等特色功能。", -1));
  335. const _hoisted_105 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h2", null, "特色功能", -1));
  336. const _hoisted_106 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("ul", null, [
  337. /* @__PURE__ */ vue.createElementVNode("li", null, [
  338. /* @__PURE__ */ vue.createTextVNode("楼中楼 "),
  339. /* @__PURE__ */ vue.createElementVNode("ol", null, [
  340. /* @__PURE__ */ vue.createElementVNode("li", null, "可按高赞排序显示"),
  341. /* @__PURE__ */ vue.createElementVNode("li", null, "可只看楼主")
  342. ])
  343. ]),
  344. /* @__PURE__ */ vue.createElementVNode("li", null, "简洁模式"),
  345. /* @__PURE__ */ vue.createElementVNode("li", null, "查看回复上下文"),
  346. /* @__PURE__ */ vue.createElementVNode("li", null, "高赞回复")
  347. ], -1));
  348. const _hoisted_107 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h2", null, "增强(辅助)功能", -1));
  349. const _hoisted_108 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("ul", null, [
  350. /* @__PURE__ */ vue.createElementVNode("li", null, "预览帖子正文"),
  351. /* @__PURE__ */ vue.createElementVNode("li", null, "弹框显示帖子正文和回复"),
  352. /* @__PURE__ */ vue.createElementVNode("li", null, "帖子显示OP注册时间"),
  353. /* @__PURE__ */ vue.createElementVNode("li", null, "链接自动转图片"),
  354. /* @__PURE__ */ vue.createElementVNode("li", null, "快捷发送贴吧表情、emoji、图片"),
  355. /* @__PURE__ */ vue.createElementVNode("li", null, "新标签页打开链接,默认打开,可单独关闭"),
  356. /* @__PURE__ */ vue.createElementVNode("li", null, "对用户打标签"),
  357. /* @__PURE__ */ vue.createElementVNode("li", null, "划词 base64 解码,支持解码中文"),
  358. /* @__PURE__ */ vue.createElementVNode("li", null, "一键@所有人,@管理员:回复时,可一键@所有人和@管理员"),
  359. /* @__PURE__ */ vue.createElementVNode("li", null, "自适应屏幕宽度,支持黑暗模式"),
  360. /* @__PURE__ */ vue.createElementVNode("li", null, "记忆上次阅读位置"),
  361. /* @__PURE__ */ vue.createElementVNode("li", null, "按钮异步请求:操作按钮(感谢、收藏、回复、隐藏)异步请求,不会刷新页面"),
  362. /* @__PURE__ */ vue.createElementVNode("li", null, "收藏时提醒添加到浏览器书签,防止账号被封无法查看收藏"),
  363. /* @__PURE__ */ vue.createElementVNode("li", null, "自动签到"),
  364. /* @__PURE__ */ vue.createElementVNode("li", null, "正文超长自动折叠")
  365. ], -1));
  366. const _hoisted_109 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("h2", null, "如何帮助我", -1));
  367. const _hoisted_110 = ["href"];
  368. const _hoisted_111 = ["href"];
  369. const _hoisted_112 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", null, [
  370. /* @__PURE__ */ vue.createTextVNode(" 更新日志:"),
  371. /* @__PURE__ */ vue.createElementVNode("a", {
  372. href: "https://greasyfork.org/zh-CN/scripts/458024/versions",
  373. target: "_blank"
  374. }, "https://greasyfork.org/zh-CN/scripts/458024/versions")
  375. ], -1));
  376. function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
  377. const _component_BaseSwitch = vue.resolveComponent("BaseSwitch");
  378. const _component_Tooltip = vue.resolveComponent("Tooltip");
  379. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  380. default: vue.withCtx(() => [
  381. $props.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, [
  382. vue.createElementVNode("div", {
  383. class: "mask",
  384. onClick: _cache[0] || (_cache[0] = (...args) => $options.close && $options.close(...args))
  385. }),
  386. vue.createElementVNode("div", _hoisted_2$f, [
  387. vue.createElementVNode("div", _hoisted_3$b, [
  388. _hoisted_4$b,
  389. vue.createElementVNode("i", {
  390. class: "fa fa-times",
  391. onClick: _cache[1] || (_cache[1] = (...args) => $options.close && $options.close(...args))
  392. })
  393. ]),
  394. vue.createElementVNode("div", _hoisted_5$8, [
  395. vue.createElementVNode("div", _hoisted_6$8, [
  396. vue.createElementVNode("div", _hoisted_7$7, [
  397. vue.createElementVNode("div", {
  398. class: vue.normalizeClass(["tab", $data.tabIndex === 0 && "active"]),
  399. onClick: _cache[2] || (_cache[2] = ($event) => $data.tabIndex = 0)
  400. }, _hoisted_9$7, 2),
  401. vue.createElementVNode("div", {
  402. class: vue.normalizeClass(["tab", $data.tabIndex === 1 && "active"]),
  403. onClick: _cache[3] || (_cache[3] = ($event) => $data.tabIndex = 1)
  404. }, _hoisted_11$6, 2),
  405. vue.createElementVNode("div", {
  406. class: vue.normalizeClass(["tab", $data.tabIndex === 2 && "active"]),
  407. onClick: _cache[4] || (_cache[4] = ($event) => $data.tabIndex = 2)
  408. }, _hoisted_13$6, 2),
  409. vue.createElementVNode("div", {
  410. class: vue.normalizeClass(["tab", $data.tabIndex === 3 && "active"]),
  411. onClick: _cache[5] || (_cache[5] = ($event) => $data.tabIndex = 3)
  412. }, _hoisted_15$6, 2)
  413. ])
  414. ]),
  415. vue.createElementVNode("div", _hoisted_16$6, [
  416. vue.createElementVNode("div", _hoisted_17$5, [
  417. $data.tabIndex === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18$5, [
  418. vue.createElementVNode("div", _hoisted_19$4, [
  419. _hoisted_20$4,
  420. vue.createElementVNode("div", _hoisted_21$4, [
  421. vue.createElementVNode("div", _hoisted_22$3, [
  422. vue.createElementVNode("div", {
  423. class: vue.normalizeClass(["radio", $data.config.viewType === "simple" ? "active" : ""]),
  424. onClick: _cache[6] || (_cache[6] = ($event) => $data.config.viewType = "simple")
  425. }, "简洁 ", 2),
  426. vue.createElementVNode("div", {
  427. class: vue.normalizeClass(["radio", $data.config.viewType === "table" ? "active" : ""]),
  428. onClick: _cache[7] || (_cache[7] = ($event) => $data.config.viewType = "table")
  429. }, "表格 ", 2),
  430. vue.createElementVNode("div", {
  431. class: vue.normalizeClass(["radio", $data.config.viewType === "card" ? "active" : ""]),
  432. onClick: _cache[8] || (_cache[8] = ($event) => $data.config.viewType = "card")
  433. }, "卡片 ", 2)
  434. ])
  435. ])
  436. ]),
  437. _hoisted_23$3,
  438. vue.createElementVNode("div", _hoisted_24$2, [
  439. _hoisted_25$3,
  440. vue.createElementVNode("div", _hoisted_26$2, [
  441. vue.createVNode(_component_BaseSwitch, {
  442. modelValue: $data.config.showPreviewBtn,
  443. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => $data.config.showPreviewBtn = $event)
  444. }, null, 8, ["modelValue"])
  445. ])
  446. ]),
  447. _hoisted_27$1,
  448. vue.createElementVNode("div", _hoisted_28$1, [
  449. _hoisted_29$1,
  450. vue.createElementVNode("div", _hoisted_30$1, [
  451. vue.createVNode(_component_BaseSwitch, {
  452. modelValue: $data.config.clickPostItemOpenDetail,
  453. "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => $data.config.clickPostItemOpenDetail = $event)
  454. }, null, 8, ["modelValue"])
  455. ])
  456. ]),
  457. _hoisted_31$1,
  458. vue.createElementVNode("div", _hoisted_32$1, [
  459. _hoisted_33$1,
  460. vue.createElementVNode("div", _hoisted_34$1, [
  461. vue.createVNode(_component_BaseSwitch, {
  462. modelValue: $data.config.newTabOpen,
  463. "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => $data.config.newTabOpen = $event)
  464. }, null, 8, ["modelValue"])
  465. ])
  466. ]),
  467. _hoisted_35$1
  468. ])) : vue.createCommentVNode("", true),
  469. $data.tabIndex === 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_36$1, [
  470. vue.createElementVNode("div", _hoisted_37$1, [
  471. _hoisted_38$1,
  472. vue.createElementVNode("div", _hoisted_39$1, [
  473. vue.createVNode(_component_BaseSwitch, {
  474. modelValue: $data.config.showToolbar,
  475. "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => $data.config.showToolbar = $event)
  476. }, null, 8, ["modelValue"])
  477. ])
  478. ]),
  479. vue.createElementVNode("div", _hoisted_40$1, [
  480. _hoisted_41$1,
  481. vue.createElementVNode("div", _hoisted_42$1, [
  482. vue.createElementVNode("div", _hoisted_43$1, [
  483. vue.createVNode(_component_Tooltip, { title: "不隐藏@用户" }, {
  484. default: vue.withCtx(() => [
  485. vue.createElementVNode("div", {
  486. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.FloorInFloor ? "active" : ""]),
  487. onClick: _cache[13] || (_cache[13] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.FloorInFloor)
  488. }, "楼中楼(@) ", 2)
  489. ]),
  490. _: 1
  491. }),
  492. vue.createVNode(_component_Tooltip, { title: "隐藏第一个@用户,双击内容可显示原文" }, {
  493. default: vue.withCtx(() => [
  494. vue.createElementVNode("div", {
  495. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.FloorInFloorNoCallUser ? "active" : ""]),
  496. onClick: _cache[14] || (_cache[14] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.FloorInFloorNoCallUser)
  497. }, " 楼中楼 ", 2)
  498. ]),
  499. _: 1
  500. }),
  501. vue.createVNode(_component_Tooltip, { title: "重复显示楼中楼的回复" }, {
  502. default: vue.withCtx(() => [
  503. vue.createElementVNode("div", {
  504. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.FloorInFloorNested ? "active" : ""]),
  505. onClick: _cache[15] || (_cache[15] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.FloorInFloorNested)
  506. }, " 冗余楼中楼 ", 2)
  507. ]),
  508. _: 1
  509. }),
  510. vue.createElementVNode("div", {
  511. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.Like ? "active" : ""]),
  512. onClick: _cache[16] || (_cache[16] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.Like)
  513. }, "感谢 ", 2),
  514. vue.createElementVNode("div", {
  515. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.OnlyOp ? "active" : ""]),
  516. onClick: _cache[17] || (_cache[17] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.OnlyOp)
  517. }, "只看楼主 ", 2),
  518. vue.createElementVNode("div", {
  519. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === $options.CommentDisplayType.V2exOrigin ? "active" : ""]),
  520. onClick: _cache[18] || (_cache[18] = ($event) => $data.config.commentDisplayType = $options.CommentDisplayType.V2exOrigin)
  521. }, "V2原版 ", 2)
  522. ])
  523. ])
  524. ]),
  525. vue.createElementVNode("div", _hoisted_44$1, [
  526. _hoisted_45$1,
  527. vue.createElementVNode("div", _hoisted_46$1, [
  528. vue.createVNode(_component_BaseSwitch, {
  529. modelValue: $data.config.autoOpenDetail,
  530. "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => $data.config.autoOpenDetail = $event)
  531. }, null, 8, ["modelValue"])
  532. ])
  533. ]),
  534. _hoisted_47$1,
  535. vue.createElementVNode("div", _hoisted_48$1, [
  536. _hoisted_49$1,
  537. vue.createElementVNode("div", _hoisted_50$1, [
  538. vue.createVNode(_component_BaseSwitch, {
  539. modelValue: $data.config.closePostDetailBySpace,
  540. "onUpdate:modelValue": _cache[20] || (_cache[20] = ($event) => $data.config.closePostDetailBySpace = $event)
  541. }, null, 8, ["modelValue"])
  542. ])
  543. ]),
  544. vue.createElementVNode("div", _hoisted_51$1, [
  545. _hoisted_52$1,
  546. vue.createElementVNode("div", _hoisted_53$1, [
  547. vue.createVNode(_component_BaseSwitch, {
  548. modelValue: $data.config.contentAutoCollapse,
  549. "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => $data.config.contentAutoCollapse = $event)
  550. }, null, 8, ["modelValue"])
  551. ])
  552. ]),
  553. vue.createElementVNode("div", _hoisted_54$1, [
  554. _hoisted_55$1,
  555. vue.createElementVNode("div", _hoisted_56$1, [
  556. vue.withDirectives(vue.createElementVNode("input", {
  557. type: "text",
  558. "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => $data.config.postWidth = $event)
  559. }, null, 512), [
  560. [vue.vModelText, $data.config.postWidth]
  561. ])
  562. ])
  563. ]),
  564. _hoisted_57$1,
  565. _hoisted_58$1,
  566. _hoisted_59$1,
  567. _hoisted_60$1,
  568. vue.createElementVNode("div", _hoisted_61$1, [
  569. _hoisted_62,
  570. vue.createElementVNode("div", _hoisted_63, [
  571. vue.createVNode(_component_BaseSwitch, {
  572. modelValue: $data.config.showTopReply,
  573. "onUpdate:modelValue": _cache[23] || (_cache[23] = ($event) => $data.config.showTopReply = $event)
  574. }, null, 8, ["modelValue"])
  575. ])
  576. ]),
  577. vue.createElementVNode("div", _hoisted_64, [
  578. _hoisted_65,
  579. vue.createElementVNode("div", _hoisted_66, [
  580. vue.withDirectives(vue.createElementVNode("input", {
  581. type: "number",
  582. min: "1",
  583. "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => $data.config.topReplyCount = $event)
  584. }, null, 512), [
  585. [vue.vModelText, $data.config.topReplyCount]
  586. ])
  587. ])
  588. ]),
  589. vue.createElementVNode("div", _hoisted_67, [
  590. _hoisted_68,
  591. vue.createElementVNode("div", _hoisted_69, [
  592. vue.withDirectives(vue.createElementVNode("input", {
  593. type: "number",
  594. min: "1",
  595. "onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => $data.config.topReplyLoveMinCount = $event)
  596. }, null, 512), [
  597. [vue.vModelText, $data.config.topReplyLoveMinCount]
  598. ])
  599. ])
  600. ]),
  601. _hoisted_70,
  602. vue.createElementVNode("div", _hoisted_71, [
  603. _hoisted_72,
  604. vue.createElementVNode("div", _hoisted_73, [
  605. vue.createVNode(_component_BaseSwitch, {
  606. "model-value": $data.config.rememberLastReadFloor,
  607. "onUpdate:modelValue": _cache[26] || (_cache[26] = ($event) => {
  608. $data.config.rememberLastReadFloor = !$data.config.rememberLastReadFloor;
  609. $data.config.autoJumpLastReadFloor = false;
  610. })
  611. }, null, 8, ["model-value"])
  612. ])
  613. ]),
  614. vue.createElementVNode("div", _hoisted_74, [
  615. _hoisted_75,
  616. vue.createElementVNode("div", _hoisted_76, [
  617. vue.createVNode(_component_BaseSwitch, {
  618. modelValue: $data.config.autoJumpLastReadFloor,
  619. "onUpdate:modelValue": _cache[27] || (_cache[27] = ($event) => $data.config.autoJumpLastReadFloor = $event)
  620. }, null, 8, ["modelValue"])
  621. ])
  622. ])
  623. ])) : vue.createCommentVNode("", true),
  624. $data.tabIndex === 2 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_77, [
  625. vue.createElementVNode("div", _hoisted_78, [
  626. _hoisted_79,
  627. vue.createElementVNode("div", _hoisted_80, [
  628. vue.createVNode(_component_BaseSwitch, {
  629. modelValue: $data.config.openTag,
  630. "onUpdate:modelValue": _cache[28] || (_cache[28] = ($event) => $data.config.openTag = $event)
  631. }, null, 8, ["modelValue"])
  632. ])
  633. ]),
  634. vue.createElementVNode("div", _hoisted_81, [
  635. _hoisted_82,
  636. vue.createElementVNode("div", _hoisted_83, [
  637. vue.createVNode(_component_BaseSwitch, {
  638. modelValue: $data.config.base64,
  639. "onUpdate:modelValue": _cache[29] || (_cache[29] = ($event) => $data.config.base64 = $event)
  640. }, null, 8, ["modelValue"])
  641. ])
  642. ]),
  643. vue.createElementVNode("div", _hoisted_84, [
  644. _hoisted_85,
  645. vue.createElementVNode("div", _hoisted_86, [
  646. vue.createVNode(_component_BaseSwitch, {
  647. modelValue: $data.config.autoSignin,
  648. "onUpdate:modelValue": _cache[30] || (_cache[30] = ($event) => $data.config.autoSignin = $event)
  649. }, null, 8, ["modelValue"])
  650. ])
  651. ]),
  652. vue.createElementVNode("div", _hoisted_87, [
  653. _hoisted_88,
  654. vue.createElementVNode("div", _hoisted_89, [
  655. vue.withDirectives(vue.createElementVNode("input", {
  656. type: "text",
  657. "onUpdate:modelValue": _cache[31] || (_cache[31] = ($event) => $data.config.customBgColor = $event)
  658. }, null, 512), [
  659. [vue.vModelText, $data.config.customBgColor]
  660. ])
  661. ])
  662. ]),
  663. _hoisted_90,
  664. _hoisted_91,
  665. vue.createElementVNode("div", _hoisted_92, [
  666. _hoisted_93,
  667. vue.createElementVNode("div", _hoisted_94, [
  668. vue.createVNode(_component_BaseSwitch, {
  669. modelValue: $data.config.collectBrowserNotice,
  670. "onUpdate:modelValue": _cache[32] || (_cache[32] = ($event) => $data.config.collectBrowserNotice = $event)
  671. }, null, 8, ["modelValue"])
  672. ])
  673. ]),
  674. _hoisted_95
  675. ])) : vue.createCommentVNode("", true),
  676. $data.tabIndex === 3 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_96, [
  677. _hoisted_97,
  678. vue.createElementVNode("div", _hoisted_98, [
  679. vue.createElementVNode("div", null, [
  680. vue.createTextVNode(" 本项目完全开源,项目地址:"),
  681. vue.createElementVNode("a", {
  682. href: $options.windowConst.git,
  683. target: "_blank"
  684. }, vue.toDisplayString($options.windowConst.git), 9, _hoisted_99),
  685. vue.createTextVNode(",目前由我一个人维护,如果您觉得好用,"),
  686. _hoisted_100
  687. ]),
  688. vue.createElementVNode("div", null, [
  689. _hoisted_101,
  690. _hoisted_102,
  691. vue.createTextVNode(" 大多只是对V2EX修修补补、美化UI,在使用体验上依旧是10年前的网站,太多脚本年久失修无人维护。楼中楼只能解析当前页,如果有多页回复,楼中楼就会前言不搭后语莫名其妙的 "),
  692. _hoisted_103,
  693. _hoisted_104,
  694. vue.createTextVNode(" 对V2EX进行了整体改造,如预览、点赞、回复、屏蔽等等都走异步请求,使用体验上已和现代网站无异,同时也集成了市面上常见的增强(辅助)功能, "),
  695. _hoisted_105,
  696. _hoisted_106,
  697. _hoisted_107,
  698. _hoisted_108,
  699. _hoisted_109,
  700. vue.createTextVNode(" 这个项目花了我很多精力,如果对您有用: 点个 "),
  701. vue.createElementVNode("a", {
  702. href: $options.windowConst.git
  703. }, "Star ⭐️", 8, _hoisted_110),
  704. vue.createTextVNode(" 或分享给他人,让更多的人知道我的存在。 "),
  705. vue.createElementVNode("div", null, [
  706. vue.createTextVNode("提供反馈,帮助我改进,以持续完善脚本。在 "),
  707. vue.createElementVNode("a", {
  708. href: $options.windowConst.issue
  709. }, "这里", 8, _hoisted_111),
  710. vue.createTextVNode(" 提出。")
  711. ]),
  712. _hoisted_112
  713. ])
  714. ])
  715. ])) : vue.createCommentVNode("", true)
  716. ])
  717. ])
  718. ])
  719. ])
  720. ])) : vue.createCommentVNode("", true)
  721. ]),
  722. _: 1
  723. });
  724. }
  725. const Setting = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["render", _sfc_render$8], ["__scopeId", "data-v-0c0fac4f"]]);
  726. const eventBus = {
  727. eventMap: /* @__PURE__ */ new Map(),
  728. on(eventType, cb) {
  729. let cbs = this.eventMap.get(eventType);
  730. if (cbs) {
  731. cbs.push(cb);
  732. } else {
  733. cbs = [cb];
  734. }
  735. this.eventMap.set(eventType, cbs);
  736. },
  737. emit(eventType, val) {
  738. let cbs = this.eventMap.get(eventType);
  739. if (cbs) {
  740. cbs.map((cb) => cb(val));
  741. }
  742. },
  743. off(eventType) {
  744. let cbs = this.eventMap.has(eventType);
  745. if (cbs) {
  746. this.eventMap.delete(eventType);
  747. }
  748. },
  749. clear() {
  750. this.eventMap = /* @__PURE__ */ new Map();
  751. }
  752. };
  753. const CMD = {
  754. SHOW_TOOLTIP: "SHOW_TOOLTIP",
  755. SHOW_MSG: "SHOW_MSG",
  756. SET_CALL: "SET_CALL",
  757. SHOW_CALL: "SHOW_CALL",
  758. REFRESH_ONCE: "REFRESH_ONCE",
  759. ADD_REPLY: "ADD_REPLY",
  760. IGNORE: "IGNORE",
  761. MERGE: "MERGE",
  762. REMOVE: "REMOVE",
  763. CHANGE_COMMENT_THANK: "CHANGE_COMMENT_THANK",
  764. CHANGE_POST_THANK: "CHANGE_POST_THANK",
  765. ADD_TAG: "ADD_TAG",
  766. REMOVE_TAG: "REMOVE_TAG",
  767. RELATION_REPLY: "RELATION_REPLY",
  768. JUMP: "JUMP",
  769. ADD_READ: "ADD_READ",
  770. REFRESH_POST: "REFRESH_POST"
  771. };
  772. const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
  773. __name: "BaseLoading",
  774. props: {
  775. size: { default: "normal" }
  776. },
  777. setup(__props) {
  778. return (_ctx, _cache) => {
  779. return vue.openBlock(), vue.createElementBlock("div", {
  780. class: vue.normalizeClass(["loading", [_ctx.size]])
  781. }, null, 2);
  782. };
  783. }
  784. });
  785. const BaseLoading = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-2697baa2"]]);
  786. const _hoisted_1$f = {
  787. key: 1,
  788. class: "key-notice"
  789. };
  790. const _hoisted_2$e = { class: "key" };
  791. const _sfc_main$f = /* @__PURE__ */ vue.defineComponent({
  792. __name: "BaseButton",
  793. props: {
  794. keyboard: {},
  795. active: { type: Boolean },
  796. disabled: { type: Boolean },
  797. loading: { type: Boolean },
  798. size: { default: "normal" },
  799. type: { default: "primary" }
  800. },
  801. emits: ["click"],
  802. setup(__props) {
  803. return (_ctx, _cache) => {
  804. return vue.openBlock(), vue.createBlock(Tooltip, {
  805. disabled: !_ctx.keyboard,
  806. title: `快捷键: ${_ctx.keyboard}`
  807. }, {
  808. default: vue.withCtx(() => [
  809. vue.createElementVNode("div", vue.mergeProps({ class: "base-button" }, _ctx.$attrs, {
  810. onClick: _cache[0] || (_cache[0] = (e2) => !_ctx.disabled && !_ctx.loading && _ctx.$emit("click", e2)),
  811. class: [
  812. _ctx.active && "active",
  813. _ctx.size,
  814. _ctx.type,
  815. (_ctx.disabled || _ctx.loading) && "disabled",
  816. !_ctx.disabled && "hvr-grow"
  817. ]
  818. }), [
  819. vue.createElementVNode("span", {
  820. style: vue.normalizeStyle({ opacity: _ctx.loading ? 0 : 1 })
  821. }, [
  822. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  823. ], 4),
  824. _ctx.loading ? (vue.openBlock(), vue.createBlock(BaseLoading, {
  825. key: 0,
  826. size: "small"
  827. })) : vue.createCommentVNode("", true),
  828. _ctx.keyboard ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$f, [
  829. vue.createElementVNode("span", _hoisted_2$e, vue.toDisplayString(_ctx.keyboard), 1)
  830. ])) : vue.createCommentVNode("", true)
  831. ], 16)
  832. ]),
  833. _: 3
  834. }, 8, ["disabled", "title"]);
  835. };
  836. }
  837. });
  838. const BaseButton = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-5a7d79ba"]]);
  839. const _sfc_main$e = {
  840. name: "PopConfirm",
  841. components: { BaseButton },
  842. props: {
  843. title: {
  844. type: String,
  845. default() {
  846. return "";
  847. }
  848. },
  849. disabled: {
  850. type: Boolean,
  851. default() {
  852. return false;
  853. }
  854. }
  855. },
  856. data() {
  857. return {
  858. show: false
  859. };
  860. },
  861. methods: {
  862. showPop(e2) {
  863. if (this.disabled)
  864. return;
  865. let rect = e2.target.getBoundingClientRect();
  866. this.show = true;
  867. vue.nextTick(() => {
  868. this.$refs.tip.style.top = rect.top + "px";
  869. this.$refs.tip.style.left = rect.left + rect.width / 2 - 50 + "px";
  870. });
  871. },
  872. confirm() {
  873. this.show = false;
  874. this.$emit("confirm");
  875. }
  876. }
  877. };
  878. const _hoisted_1$e = { class: "pop-confirm" };
  879. const _hoisted_2$d = {
  880. key: 0,
  881. ref: "tip",
  882. class: "pop-confirm-content"
  883. };
  884. const _hoisted_3$a = { class: "text" };
  885. const _hoisted_4$a = { class: "options" };
  886. function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
  887. const _component_BaseButton = vue.resolveComponent("BaseButton");
  888. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$e, [
  889. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  890. vue.createVNode(vue.Transition, null, {
  891. default: vue.withCtx(() => [
  892. $data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$d, [
  893. vue.createElementVNode("div", _hoisted_3$a, vue.toDisplayString($props.title), 1),
  894. vue.createElementVNode("div", _hoisted_4$a, [
  895. vue.createVNode(_component_BaseButton, {
  896. type: "link",
  897. size: "small",
  898. onClick: _cache[0] || (_cache[0] = ($event) => $data.show = false)
  899. }, {
  900. default: vue.withCtx(() => [
  901. vue.createTextVNode("取消")
  902. ]),
  903. _: 1
  904. }),
  905. vue.createVNode(_component_BaseButton, {
  906. size: "small",
  907. onClick: $options.confirm
  908. }, {
  909. default: vue.withCtx(() => [
  910. vue.createTextVNode("确认")
  911. ]),
  912. _: 1
  913. }, 8, ["onClick"])
  914. ])
  915. ], 512)) : vue.createCommentVNode("", true)
  916. ]),
  917. _: 1
  918. })
  919. ])),
  920. vue.createElementVNode("span", {
  921. onClick: _cache[1] || (_cache[1] = (...args) => $options.showPop && $options.showPop(...args))
  922. }, [
  923. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  924. ])
  925. ]);
  926. }
  927. const PopConfirm = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$7], ["__scopeId", "data-v-05424197"]]);
  928. const loveColor = "rgb(224,42,42)";
  929. const _sfc_main$d = {
  930. name: "Point",
  931. components: { PopConfirm },
  932. inject: ["post", "isLogin"],
  933. props: {
  934. item: {
  935. type: Object,
  936. default() {
  937. return {};
  938. }
  939. },
  940. full: {
  941. type: Boolean,
  942. default() {
  943. return true;
  944. }
  945. },
  946. apiUrl: ""
  947. },
  948. computed: {
  949. disabled() {
  950. return this.item.username === window.user.username || this.item.isThanked || !this.isLogin;
  951. }
  952. },
  953. methods: {
  954. getColor() {
  955. if (this.item.isThanked)
  956. return loveColor;
  957. return this.full ? loveColor : "#929596";
  958. },
  959. getIsFull() {
  960. if (this.item.isThanked)
  961. return loveColor;
  962. return this.full ? loveColor : "none";
  963. },
  964. thankError() {
  965. if (!this.isLogin) {
  966. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  967. }
  968. if (this.item.username === window.user.username) {
  969. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "不能感谢自己" });
  970. }
  971. if (this.item.isThanked) {
  972. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "已经感谢过了" });
  973. }
  974. },
  975. async thank() {
  976. this.$emit("addThank");
  977. let url = `${window.baseUrl}/thank/${this.apiUrl}?once=${this.post.once}`;
  978. $.post(url).then((res) => {
  979. if (!res.success) {
  980. this.$emit("recallThank");
  981. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: res.message });
  982. }
  983. eventBus.emit(CMD.REFRESH_ONCE, res.once);
  984. }, (err) => {
  985. this.$emit("recallThank");
  986. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "感谢失败" });
  987. eventBus.emit(CMD.REFRESH_ONCE);
  988. });
  989. }
  990. }
  991. };
  992. const _hoisted_1$d = {
  993. viewBox: "0 0 48 48",
  994. fill: "none",
  995. xmlns: "http://www.w3.org/2000/svg"
  996. };
  997. const _hoisted_2$c = ["fill", "stroke"];
  998. const _hoisted_3$9 = {
  999. key: 0,
  1000. class: "link-num"
  1001. };
  1002. const _hoisted_4$9 = { key: 1 };
  1003. function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
  1004. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  1005. return vue.openBlock(), vue.createBlock(_component_PopConfirm, {
  1006. disabled: $options.disabled,
  1007. title: `确认花费 10 个铜币向 @${$props.item.username} 的这条回复发送感谢?`,
  1008. onConfirm: $options.thank
  1009. }, {
  1010. default: vue.withCtx(() => [
  1011. vue.createElementVNode("div", {
  1012. class: vue.normalizeClass(["tool", $options.disabled ? "disabled" : ""]),
  1013. onClick: _cache[0] || (_cache[0] = (...args) => $options.thankError && $options.thankError(...args))
  1014. }, [
  1015. (vue.openBlock(), vue.createElementBlock("svg", _hoisted_1$d, [
  1016. vue.createElementVNode("path", {
  1017. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  1018. fill: $options.getIsFull(),
  1019. stroke: $options.getColor(),
  1020. "stroke-width": "2",
  1021. "stroke-linecap": "round",
  1022. "stroke-linejoin": "round"
  1023. }, null, 8, _hoisted_2$c)
  1024. ])),
  1025. $props.item.thankCount ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$9, vue.toDisplayString($props.item.thankCount), 1)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$9, "感谢"))
  1026. ], 2)
  1027. ]),
  1028. _: 1
  1029. }, 8, ["disabled", "title", "onConfirm"]);
  1030. }
  1031. const Point = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$6]]);
  1032. const _sfc_main$c = {
  1033. name: "Author",
  1034. components: { PopConfirm, Point },
  1035. inject: ["isLogin", "tags", "config", "isNight"],
  1036. props: {
  1037. modelValue: false,
  1038. comment: {
  1039. type: Object,
  1040. default() {
  1041. return {};
  1042. }
  1043. },
  1044. type: {
  1045. type: String,
  1046. default() {
  1047. return "list";
  1048. }
  1049. }
  1050. },
  1051. computed: {
  1052. isDev() {
  1053. return false;
  1054. },
  1055. pointInfo() {
  1056. return {
  1057. isThanked: this.comment.isThanked,
  1058. thankCount: this.comment.thankCount,
  1059. username: this.comment.username
  1060. };
  1061. },
  1062. myTags() {
  1063. return this.tags[this.comment.username] ?? [];
  1064. },
  1065. context() {
  1066. return this.comment.replyUsers.length;
  1067. }
  1068. },
  1069. methods: {
  1070. jump() {
  1071. eventBus.emit(CMD.JUMP, this.comment.floor);
  1072. },
  1073. showRelationReply() {
  1074. if (!this.comment.replyUsers.length) {
  1075. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "该回复无上下文" });
  1076. return;
  1077. }
  1078. eventBus.emit(CMD.RELATION_REPLY, {
  1079. left: this.comment.replyUsers,
  1080. right: this.comment.username,
  1081. rightFloor: this.comment.floor
  1082. });
  1083. },
  1084. addTag() {
  1085. eventBus.emit(CMD.ADD_TAG, this.comment.username);
  1086. },
  1087. removeTag(tag) {
  1088. eventBus.emit(CMD.REMOVE_TAG, { username: this.comment.username, tag });
  1089. },
  1090. checkIsLogin(emitName = "") {
  1091. if (!this.isLogin) {
  1092. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  1093. return false;
  1094. }
  1095. this.$emit(emitName);
  1096. return true;
  1097. },
  1098. addThank() {
  1099. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "add" });
  1100. },
  1101. recallThank() {
  1102. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "recall" });
  1103. }
  1104. }
  1105. };
  1106. const _withScopeId$a = (n2) => (vue.pushScopeId("data-v-c450f45f"), n2 = n2(), vue.popScopeId(), n2);
  1107. const _hoisted_1$c = { class: "Author-left" };
  1108. const _hoisted_2$b = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1109. d: "M22 42H6V26",
  1110. stroke: "#177EC9",
  1111. "stroke-width": "4",
  1112. "stroke-linecap": "round",
  1113. "stroke-linejoin": "round"
  1114. }, null, -1));
  1115. const _hoisted_3$8 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1116. d: "M26 6H42V22",
  1117. stroke: "#177EC9",
  1118. "stroke-width": "4",
  1119. "stroke-linecap": "round",
  1120. "stroke-linejoin": "round"
  1121. }, null, -1));
  1122. const _hoisted_4$8 = [
  1123. _hoisted_2$b,
  1124. _hoisted_3$8
  1125. ];
  1126. const _hoisted_5$7 = ["href"];
  1127. const _hoisted_6$7 = ["src"];
  1128. const _hoisted_7$6 = { class: "texts" };
  1129. const _hoisted_8$6 = ["href"];
  1130. const _hoisted_9$6 = {
  1131. key: 0,
  1132. class: "owner"
  1133. };
  1134. const _hoisted_10$5 = {
  1135. key: 1,
  1136. class: "dup"
  1137. };
  1138. const _hoisted_11$5 = {
  1139. key: 2,
  1140. class: "mod"
  1141. };
  1142. const _hoisted_12$5 = { class: "ago" };
  1143. const _hoisted_13$5 = { class: "my-tag" };
  1144. const _hoisted_14$5 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  1145. const _hoisted_15$5 = ["onClick"];
  1146. const _hoisted_16$5 = { class: "Author-right" };
  1147. const _hoisted_17$4 = {
  1148. key: 0,
  1149. class: "toolbar"
  1150. };
  1151. const _hoisted_18$4 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "tool" }, [
  1152. /* @__PURE__ */ vue.createElementVNode("span", null, "隐藏")
  1153. ], -1));
  1154. const _hoisted_19$3 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上下文", -1));
  1155. const _hoisted_20$3 = [
  1156. _hoisted_19$3
  1157. ];
  1158. const _hoisted_21$3 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  1159. const _hoisted_22$2 = [
  1160. _hoisted_21$3
  1161. ];
  1162. const _hoisted_23$2 = /* @__PURE__ */ vue.createStaticVNode('<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-c450f45f><path d="M4 6H44V36H29L24 41L19 36H4V6Z" fill="none" stroke="#929596" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-c450f45f></path><path d="M23 21H25.0025" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c450f45f></path><path d="M33.001 21H34.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c450f45f></path><path d="M13.001 21H14.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c450f45f></path></svg><span data-v-c450f45f>回复</span>', 2);
  1163. const _hoisted_25$2 = [
  1164. _hoisted_23$2
  1165. ];
  1166. function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
  1167. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  1168. const _component_Point = vue.resolveComponent("Point");
  1169. return vue.openBlock(), vue.createElementBlock("div", {
  1170. class: vue.normalizeClass(["Author", { expand: !$props.modelValue }])
  1171. }, [
  1172. vue.createElementVNode("div", _hoisted_1$c, [
  1173. !$props.modelValue ? (vue.openBlock(), vue.createElementBlock("svg", {
  1174. key: 0,
  1175. class: "expand-icon",
  1176. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", true)),
  1177. width: "24",
  1178. height: "24",
  1179. viewBox: "0 0 48 48",
  1180. fill: "none",
  1181. xmlns: "http://www.w3.org/2000/svg"
  1182. }, _hoisted_4$8)) : vue.createCommentVNode("", true),
  1183. $options.config.viewType !== "simple" ? (vue.openBlock(), vue.createElementBlock("a", {
  1184. key: 1,
  1185. class: "avatar",
  1186. href: `/member/${$props.comment.username}`
  1187. }, [
  1188. vue.createElementVNode("img", {
  1189. src: $props.comment.avatar,
  1190. alt: ""
  1191. }, null, 8, _hoisted_6$7)
  1192. ], 8, _hoisted_5$7)) : vue.createCommentVNode("", true),
  1193. vue.createElementVNode("span", _hoisted_7$6, [
  1194. vue.createElementVNode("strong", null, [
  1195. vue.createElementVNode("a", {
  1196. href: `/member/${$props.comment.username}`,
  1197. class: vue.normalizeClass(["username", { "dark": $options.isNight }])
  1198. }, vue.toDisplayString($props.comment.username), 11, _hoisted_8$6)
  1199. ]),
  1200. $props.comment.isOp ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$6, "OP")) : vue.createCommentVNode("", true),
  1201. $props.comment.isDup ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$5, "DUP")) : vue.createCommentVNode("", true),
  1202. $props.comment.isMod ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$5, "MOD")) : vue.createCommentVNode("", true),
  1203. vue.createElementVNode("span", _hoisted_12$5, vue.toDisplayString($props.comment.date), 1),
  1204. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 3 }, [
  1205. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  1206. return vue.openBlock(), vue.createElementBlock("span", _hoisted_13$5, [
  1207. _hoisted_14$5,
  1208. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  1209. vue.createElementVNode("i", {
  1210. class: "fa fa-trash-o remove",
  1211. onClick: ($event) => $options.removeTag(i)
  1212. }, null, 8, _hoisted_15$5)
  1213. ]);
  1214. }), 256)),
  1215. vue.createElementVNode("span", {
  1216. class: "add-tag ago",
  1217. onClick: _cache[1] || (_cache[1] = (...args) => $options.addTag && $options.addTag(...args)),
  1218. title: "添加标签"
  1219. }, "+")
  1220. ], 64)) : vue.createCommentVNode("", true)
  1221. ])
  1222. ]),
  1223. vue.createElementVNode("div", _hoisted_16$5, [
  1224. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_17$4, [
  1225. vue.createVNode(_component_PopConfirm, {
  1226. title: "确认隐藏这条回复?",
  1227. onConfirm: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("hide"))
  1228. }, {
  1229. default: vue.withCtx(() => [
  1230. _hoisted_18$4
  1231. ]),
  1232. _: 1
  1233. }),
  1234. $options.context ? (vue.openBlock(), vue.createElementBlock("div", {
  1235. key: 0,
  1236. class: "tool",
  1237. onClick: _cache[3] || (_cache[3] = (...args) => $options.showRelationReply && $options.showRelationReply(...args))
  1238. }, _hoisted_20$3)) : vue.createCommentVNode("", true),
  1239. $props.type === "top" ? (vue.openBlock(), vue.createElementBlock("div", {
  1240. key: 1,
  1241. class: "tool",
  1242. onClick: _cache[4] || (_cache[4] = (...args) => $options.jump && $options.jump(...args))
  1243. }, _hoisted_22$2)) : vue.createCommentVNode("", true),
  1244. vue.createElementVNode("div", {
  1245. class: "tool",
  1246. onClick: _cache[5] || (_cache[5] = ($event) => $options.checkIsLogin("reply"))
  1247. }, _hoisted_25$2),
  1248. vue.withDirectives(vue.createVNode(_component_Point, {
  1249. item: $options.pointInfo,
  1250. onAddThank: $options.addThank,
  1251. onRecallThank: $options.recallThank,
  1252. "api-url": "reply/" + $props.comment.id
  1253. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  1254. [vue.vShow, !$props.comment.thankCount]
  1255. ])
  1256. ])) : vue.createCommentVNode("", true),
  1257. vue.withDirectives(vue.createVNode(_component_Point, {
  1258. style: { "margin-left": "1rem" },
  1259. item: $options.pointInfo,
  1260. onAddThank: $options.addThank,
  1261. onRecallThank: $options.recallThank,
  1262. "api-url": "reply/" + $props.comment.id
  1263. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  1264. [vue.vShow, $props.comment.thankCount]
  1265. ]),
  1266. vue.createElementVNode("div", {
  1267. class: vue.normalizeClass(["floor", { isDev: $options.isDev }])
  1268. }, vue.toDisplayString($props.comment.floor), 3)
  1269. ])
  1270. ], 2);
  1271. }
  1272. const Author = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["render", _sfc_render$5], ["__scopeId", "data-v-c450f45f"]]);
  1273. const _withScopeId$9 = (n2) => (vue.pushScopeId("data-v-fb753464"), n2 = n2(), vue.popScopeId(), n2);
  1274. const _hoisted_1$b = { class: "get-cursor" };
  1275. const _hoisted_2$a = ["innerHTML"];
  1276. const _hoisted_3$7 = { class: "toolbar" };
  1277. const _hoisted_4$7 = { class: "left" };
  1278. const _hoisted_5$6 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1279. d: "M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z",
  1280. fill: "none",
  1281. stroke: "#929596",
  1282. "stroke-width": "2",
  1283. "stroke-linejoin": "round"
  1284. }, null, -1));
  1285. const _hoisted_6$6 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1286. d: "M24 35C29 35 31 31 31 31H17C17 31 19 35 24 35Z",
  1287. stroke: "#929596",
  1288. "stroke-width": "2",
  1289. "stroke-linecap": "round",
  1290. "stroke-linejoin": "round"
  1291. }, null, -1));
  1292. const _hoisted_7$5 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1293. d: "M31 18V22",
  1294. stroke: "#929596",
  1295. "stroke-width": "2",
  1296. "stroke-linecap": "round",
  1297. "stroke-linejoin": "round"
  1298. }, null, -1));
  1299. const _hoisted_8$5 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("path", {
  1300. d: "M17 18V22",
  1301. stroke: "#929596",
  1302. "stroke-width": "2",
  1303. "stroke-linecap": "round",
  1304. "stroke-linejoin": "round"
  1305. }, null, -1));
  1306. const _hoisted_9$5 = [
  1307. _hoisted_5$6,
  1308. _hoisted_6$6,
  1309. _hoisted_7$5,
  1310. _hoisted_8$5
  1311. ];
  1312. const _hoisted_10$4 = { class: "upload" };
  1313. const _hoisted_11$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  1314. width: "20",
  1315. height: "20",
  1316. viewBox: "0 0 48 48",
  1317. fill: "none",
  1318. xmlns: "http://www.w3.org/2000/svg"
  1319. }, [
  1320. /* @__PURE__ */ vue.createElementVNode("path", {
  1321. "fill-rule": "evenodd",
  1322. "clip-rule": "evenodd",
  1323. d: "M5 10C5 8.89543 5.89543 8 7 8L41 8C42.1046 8 43 8.89543 43 10V38C43 39.1046 42.1046 40 41 40H7C5.89543 40 5 39.1046 5 38V10Z",
  1324. stroke: "#929596",
  1325. "stroke-width": "2",
  1326. "stroke-linecap": "round",
  1327. "stroke-linejoin": "round"
  1328. }),
  1329. /* @__PURE__ */ vue.createElementVNode("path", {
  1330. "fill-rule": "evenodd",
  1331. "clip-rule": "evenodd",
  1332. d: "M14.5 18C15.3284 18 16 17.3284 16 16.5C16 15.6716 15.3284 15 14.5 15C13.6716 15 13 15.6716 13 16.5C13 17.3284 13.6716 18 14.5 18Z",
  1333. stroke: "#929596",
  1334. "stroke-width": "2",
  1335. "stroke-linecap": "round",
  1336. "stroke-linejoin": "round"
  1337. }),
  1338. /* @__PURE__ */ vue.createElementVNode("path", {
  1339. d: "M15 24L20 28L26 21L43 34V38C43 39.1046 42.1046 40 41 40H7C5.89543 40 5 39.1046 5 38V34L15 24Z",
  1340. fill: "none",
  1341. stroke: "#929596",
  1342. "stroke-width": "2",
  1343. "stroke-linejoin": "round"
  1344. })
  1345. ], -1));
  1346. const _hoisted_12$4 = {
  1347. key: 0,
  1348. style: { "color": "black", "font-size": "1.4rem" }
  1349. };
  1350. const _hoisted_13$4 = { class: "right" };
  1351. const _hoisted_14$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, "经典表情", -1));
  1352. const _hoisted_15$4 = { class: "list" };
  1353. const _hoisted_16$4 = ["src", "onClick"];
  1354. const _hoisted_17$3 = { class: "emoji" };
  1355. const _hoisted_18$3 = { class: "title" };
  1356. const _hoisted_19$2 = { class: "list" };
  1357. const _hoisted_20$2 = ["onClick"];
  1358. const _sfc_main$b = {
  1359. __name: "PostEditor",
  1360. props: {
  1361. replyUser: null,
  1362. replyFloor: null,
  1363. useType: {
  1364. type: String,
  1365. default() {
  1366. return "reply-comment";
  1367. }
  1368. }
  1369. },
  1370. emits: ["close"],
  1371. setup(__props, { expose: __expose, emit: __emit }) {
  1372. const props = __props;
  1373. const { replyUser, replyFloor, useType } = props;
  1374. const replyInfo = replyUser ? `@${replyUser} #${replyFloor} ` : "";
  1375. const emits = __emit;
  1376. const post = vue.inject("post");
  1377. const show = vue.inject("show");
  1378. const isNight = vue.inject("isNight");
  1379. vue.inject("pageType");
  1380. const allReplyUsers = vue.inject("allReplyUsers");
  1381. let isFocus = vue.ref(false);
  1382. const loading = vue.ref(false);
  1383. const uploadLoading = vue.ref(false);
  1384. const isShowEmoticons = vue.ref(false);
  1385. const editorId = vue.ref("editorId_" + Date.now());
  1386. const content = vue.ref(replyInfo);
  1387. const txtRef = vue.ref(null);
  1388. const cursorRef = vue.ref(null);
  1389. const emoticonsRef = vue.ref(null);
  1390. const none = vue.ref('<span style="white-space:pre-wrap;"> </span>');
  1391. const emojiEmoticons = [
  1392. {
  1393. title: "小黄脸",
  1394. list: [
  1395. "😀",
  1396. "😁",
  1397. "😂",
  1398. "🤣",
  1399. "😅",
  1400. "😊",
  1401. "😋",
  1402. "😘",
  1403. "🥰",
  1404. "😗",
  1405. "🤩",
  1406. "🤔",
  1407. "🤨",
  1408. "😐",
  1409. "😑",
  1410. "🙄",
  1411. "😏",
  1412. "😪",
  1413. "😫",
  1414. "🥱",
  1415. "😜",
  1416. "😒",
  1417. "😔",
  1418. "😨",
  1419. "😰",
  1420. "😱",
  1421. "🥵",
  1422. "😡",
  1423. "🥳",
  1424. "🥺",
  1425. "🤭",
  1426. "🧐",
  1427. "😎",
  1428. "🤓",
  1429. "😭",
  1430. "🤑",
  1431. "🤮"
  1432. ]
  1433. },
  1434. {
  1435. title: "手势",
  1436. list: [
  1437. "🙋",
  1438. "🙎",
  1439. "🙅",
  1440. "🙇",
  1441. "🤷",
  1442. "🤏",
  1443. "👉",
  1444. "✌️",
  1445. "🤘",
  1446. "🤙",
  1447. "👌",
  1448. "🤌",
  1449. "👍",
  1450. "👎",
  1451. "👋",
  1452. "🤝",
  1453. "🙏",
  1454. "👏"
  1455. ]
  1456. },
  1457. {
  1458. title: "庆祝",
  1459. list: ["✨", "🎉", "🎊"]
  1460. },
  1461. {
  1462. title: "其他",
  1463. list: ["👻", "🤡", "🐔", "👀", "💩", "🐴", "🦄", "🐧", "🐶", "🐒", "🙈", "🙉", "🙊", "🐵"]
  1464. }
  1465. ];
  1466. const classicsEmoticons = [
  1467. {
  1468. name: "[狗头]",
  1469. low: "https://i.imgur.com/io2SM1h.png",
  1470. high: "https://i.imgur.com/0icl60r.png"
  1471. },
  1472. {
  1473. name: "[马]",
  1474. low: "https://i.imgur.com/8EKZv7I.png",
  1475. high: "https://i.imgur.com/ANFUX52.png"
  1476. },
  1477. {
  1478. name: "[不高兴]",
  1479. low: "https://i.imgur.com/huX6coX.png",
  1480. high: "https://i.imgur.com/N7JEuvc.png"
  1481. },
  1482. {
  1483. name: "[呵呵]",
  1484. low: "https://i.imgur.com/RvoLAbX.png",
  1485. high: "https://i.imgur.com/xSzIqrK.png"
  1486. },
  1487. {
  1488. name: "[真棒]",
  1489. low: "https://i.imgur.com/xr1UOz1.png",
  1490. high: "https://i.imgur.com/w8YEw9Q.png"
  1491. },
  1492. {
  1493. name: "[鄙视]",
  1494. low: "https://i.imgur.com/u6jlqVq.png",
  1495. high: "https://i.imgur.com/8JFNANq.png"
  1496. },
  1497. {
  1498. name: "[疑问]",
  1499. low: "https://i.imgur.com/F29pmQ6.png",
  1500. high: "https://i.imgur.com/EbbTQAR.png"
  1501. },
  1502. {
  1503. name: "[吐舌]",
  1504. low: "https://i.imgur.com/InmIzl9.png",
  1505. high: "https://i.imgur.com/Ovj56Cd.png"
  1506. },
  1507. // {
  1508. // name: '[嘲笑]',
  1509. // low: 'https://i.imgur.com/BaWcsMR.png',
  1510. // high: 'https://i.imgur.com/0OGfJw4.png'
  1511. // },
  1512. // {
  1513. // name: '[滑稽]',
  1514. // low: 'https://i.imgur.com/lmbN0yI.png',
  1515. // high: 'https://i.imgur.com/Pc0wH85.png'
  1516. // },
  1517. {
  1518. name: "[笑眼]",
  1519. low: "https://i.imgur.com/ZveiiGy.png",
  1520. high: "https://i.imgur.com/PI1CfEr.png"
  1521. },
  1522. {
  1523. name: "[狂汗]",
  1524. low: "https://i.imgur.com/veWihk6.png",
  1525. high: "https://i.imgur.com/3LtHdQv.png"
  1526. },
  1527. {
  1528. name: "[大哭]",
  1529. low: "https://i.imgur.com/hu4oR6C.png",
  1530. high: "https://i.imgur.com/b4X9XLE.png"
  1531. },
  1532. {
  1533. name: "[喷]",
  1534. low: "https://i.imgur.com/bkw3VRr.png",
  1535. high: "https://i.imgur.com/wnZL13L.png"
  1536. },
  1537. {
  1538. name: "[苦笑]",
  1539. low: "https://i.imgur.com/VUWFktU.png",
  1540. high: "https://i.imgur.com/NAfspZ1.png"
  1541. },
  1542. {
  1543. name: "[喝酒]",
  1544. low: "https://i.imgur.com/2ZZSapE.png",
  1545. high: "https://i.imgur.com/rVbSVak.png"
  1546. },
  1547. {
  1548. name: "[吃瓜]",
  1549. low: "https://i.imgur.com/ee8Lq7H.png",
  1550. high: "https://i.imgur.com/0L26og9.png"
  1551. },
  1552. {
  1553. name: "[捂脸]",
  1554. low: "https://i.imgur.com/krir4IG.png",
  1555. high: "https://i.imgur.com/qqBqgVm.png"
  1556. },
  1557. {
  1558. name: "[呕]",
  1559. low: "https://i.imgur.com/6CUiUxv.png",
  1560. high: "https://i.imgur.com/kgdxRsG.png"
  1561. },
  1562. {
  1563. name: "[阴险]",
  1564. low: "https://i.imgur.com/MA8YqTP.png",
  1565. high: "https://i.imgur.com/e94jbaT.png"
  1566. },
  1567. {
  1568. name: "[怒]",
  1569. low: "https://i.imgur.com/n4kWfGB.png",
  1570. high: "https://i.imgur.com/iMXxNxh.png"
  1571. },
  1572. {
  1573. name: "[衰]",
  1574. low: "https://i.imgur.com/voHFDyQ.png",
  1575. high: "https://i.imgur.com/XffE6gu.png"
  1576. },
  1577. {
  1578. name: "[合十]",
  1579. low: "https://i.imgur.com/I8x3ang.png",
  1580. high: "https://i.imgur.com/T4rJVee.png"
  1581. },
  1582. {
  1583. name: "[赞]",
  1584. low: "https://i.imgur.com/lG44yUl.png",
  1585. high: "https://i.imgur.com/AoF5PLp.png"
  1586. },
  1587. {
  1588. name: "[踩]",
  1589. low: "https://i.imgur.com/cJp0uKZ.png",
  1590. high: "https://i.imgur.com/1XYGfXj.png"
  1591. },
  1592. {
  1593. name: "[爱心]",
  1594. low: "https://i.imgur.com/sLENaF5.png",
  1595. high: "https://i.imgur.com/dND56oX.png"
  1596. },
  1597. {
  1598. name: "[心碎]",
  1599. low: "https://i.imgur.com/AZxJzve.png",
  1600. high: "https://i.imgur.com/RiUsPci.png"
  1601. }
  1602. ];
  1603. const imgurClientIdPool = [
  1604. "3107b9ef8b316f3",
  1605. "442b04f26eefc8a",
  1606. "59cfebe717c09e4",
  1607. "60605aad4a62882",
  1608. "6c65ab1d3f5452a",
  1609. "83e123737849aa9",
  1610. "9311f6be1c10160",
  1611. "c4a4a563f698595",
  1612. "81be04b9e4a08ce"
  1613. ];
  1614. __expose({ content, isFocus: () => isFocus.value });
  1615. const editorClass = vue.computed(() => {
  1616. return [useType, isFocus.value ? "isFocus" : "", isNight.value ? "isNight" : ""];
  1617. });
  1618. const cursorHtml = vue.computed(() => {
  1619. var _a;
  1620. if (!txtRef.value || !content.value)
  1621. return "";
  1622. let index = ((_a = txtRef.value) == null ? void 0 : _a.selectionStart) || 0;
  1623. return content.value.substring(0, index).replace(/</g, "<").replace(/>/g, ">").replace(/\n/g, "<br/>").replace(/\s/g, none.value);
  1624. });
  1625. const disabled = vue.computed(() => {
  1626. if (content.value) {
  1627. return content.value === replyInfo;
  1628. } else {
  1629. return true;
  1630. }
  1631. });
  1632. function drop(e2) {
  1633. e2.preventDefault();
  1634. upload(e2.dataTransfer.files[0]);
  1635. }
  1636. async function upload(file) {
  1637. if (!file)
  1638. return;
  1639. if (uploadLoading.value)
  1640. return;
  1641. uploadLoading.value = true;
  1642. const formData = new FormData();
  1643. formData.append("image", file);
  1644. const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
  1645. const clidenId = imgurClientIdPool[randomIndex];
  1646. const res = await fetch("https://api.imgur.com/3/upload", {
  1647. method: "POST",
  1648. headers: { Authorization: `Client-ID ${clidenId}` },
  1649. body: formData
  1650. });
  1651. uploadLoading.value = false;
  1652. if (res.ok) {
  1653. const resData = await res.json();
  1654. if (resData.success) {
  1655. return insert(" " + resData.data.link + " ");
  1656. }
  1657. }
  1658. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "上传失败" });
  1659. }
  1660. async function submit() {
  1661. if (disabled.value || loading.value)
  1662. return;
  1663. loading.value = true;
  1664. let submit_content = content.value.replace(/\[((?!\[).)+\]/g, function(match) {
  1665. let item2 = classicsEmoticons.find((v) => v.name === match);
  1666. if (item2) {
  1667. return item2.low + " ";
  1668. }
  1669. return match;
  1670. });
  1671. let show_content = content.value.replace(/https?:\/\/(i\.)?imgur\.com\/((?!http).)+\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)/g, function(match) {
  1672. return `<img src="${match}" data-originUrl="${match}" data-notice="这个img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`;
  1673. });
  1674. show_content = show_content.replace(/\[((?!\[).)+\]/g, function(match) {
  1675. let item2 = classicsEmoticons.find((v) => v.name === match);
  1676. if (item2) {
  1677. return `<a target="_blank" href="${item2.low}" rel="nofollow noopener"><img src="${item2.low}" class="embedded_image" rel="noreferrer"></a> `;
  1678. }
  1679. return match;
  1680. });
  1681. let matchUsers = show_content.match(/@([\w]+?[\s])/g);
  1682. if (matchUsers) {
  1683. matchUsers.map((i) => {
  1684. let username = i.replace("@", "").replace(" ", "");
  1685. show_content = show_content.replace(username, `<a href="/member/${username}">${username}</a>`);
  1686. });
  1687. }
  1688. show_content = show_content.replaceAll("\n", "<br/>");
  1689. let item = {
  1690. thankCount: 0,
  1691. isThanked: false,
  1692. isOp: post.value.username === window.user.username,
  1693. isDup: false,
  1694. id: Date.now(),
  1695. username: window.user.username,
  1696. avatar: window.user.avatar,
  1697. date: "几秒前",
  1698. floor: post.value.replyCount + 1,
  1699. reply_content: show_content ?? "",
  1700. children: [],
  1701. replyUsers: replyUser ? [replyUser] : [],
  1702. replyFloor: replyFloor || -1,
  1703. level: useType === "reply-comment" ? 1 : 0
  1704. };
  1705. item.hideCallUserReplyContent = item.reply_content;
  1706. if (item.replyUsers.length === 1) {
  1707. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(\s#[\d]+)?\s(<br>)?/, () => "");
  1708. }
  1709. console.log("回复", item);
  1710. let url = `${window.baseUrl}/t/${post.value.id}`;
  1711. $.post(url, { content: submit_content, once: post.value.once }).then(
  1712. // $.post(url, {content: submit_content, once: 123}).then(
  1713. (res) => {
  1714. loading.value = false;
  1715. let r2 = res.search("你上一条回复的内容和这条相同");
  1716. if (r2 > -1)
  1717. return eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你上一条回复的内容和这条相同" });
  1718. r2 = res.search("请不要在每一个回复中都包括外链,这看起来像是在 spamming");
  1719. if (r2 > -1)
  1720. return eventBus.emit(CMD.SHOW_MSG, {
  1721. type: "error",
  1722. text: "请不要在每一个回复中都包括外链,这看起来像是在 spamming"
  1723. });
  1724. let r22 = res.search("创建新回复");
  1725. if (r22 > -1) {
  1726. eventBus.emit(CMD.REFRESH_ONCE, res);
  1727. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复出现了问题,请使用原版进行回复" });
  1728. let clientWidth = window.document.body.clientWidth;
  1729. let windowWidth = 1200;
  1730. let left = clientWidth / 2 - windowWidth / 2;
  1731. let newWin = window.open("创建新回复", "", `width=${windowWidth},height=600,left=${left},top=100`);
  1732. newWin.document.write(res);
  1733. let loop = setInterval(function() {
  1734. if (newWin.closed) {
  1735. clearInterval(loop);
  1736. eventBus.emit(CMD.REFRESH_POST);
  1737. }
  1738. }, 1e3);
  1739. return;
  1740. }
  1741. content.value = replyInfo;
  1742. emits("close");
  1743. eventBus.emit(CMD.REFRESH_ONCE, res);
  1744. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "回复成功" });
  1745. eventBus.emit(CMD.ADD_REPLY, item);
  1746. },
  1747. (err) => {
  1748. console.log("err", err);
  1749. loading.value = false;
  1750. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
  1751. }
  1752. ).catch((r2) => {
  1753. console.log("catch", r2);
  1754. });
  1755. }
  1756. function showEmoticons(e2) {
  1757. if (isShowEmoticons.value) {
  1758. return isShowEmoticons.value = false;
  1759. }
  1760. let rect = e2.currentTarget.getBoundingClientRect();
  1761. emoticonsRef.value.style.left = rect.left + 30 + "px";
  1762. emoticonsRef.value.style.bottom = window.innerHeight - rect.top - 20 + "px";
  1763. isShowEmoticons.value = true;
  1764. }
  1765. function off() {
  1766. eventBus.emit(CMD.SHOW_CALL, { show: false });
  1767. eventBus.off(CMD.SET_CALL);
  1768. }
  1769. function checkHeight2() {
  1770. txtRef.value.style.height = 0;
  1771. txtRef.value.style.height = txtRef.value.scrollHeight + "px";
  1772. }
  1773. function insert(str) {
  1774. let cursorPos = txtRef.value.selectionStart;
  1775. let start = content.value.slice(0, cursorPos);
  1776. let end = content.value.slice(cursorPos, content.value.length);
  1777. content.value = start + str + end;
  1778. let moveCursorPos = start.length + str.length;
  1779. setTimeout(() => {
  1780. txtRef.value.focus();
  1781. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  1782. checkHeight2();
  1783. });
  1784. }
  1785. function showCallPopover(text) {
  1786. let r2 = cursorRef.value.getBoundingClientRect();
  1787. eventBus.emit(CMD.SHOW_CALL, { show: true, top: r2.top, left: r2.left, text });
  1788. eventBus.off(CMD.SET_CALL);
  1789. eventBus.on(CMD.SET_CALL, (e2) => {
  1790. let cursorPos = txtRef.value.selectionStart;
  1791. let start = content.value.slice(0, cursorPos);
  1792. let end = content.value.slice(cursorPos, content.value.length);
  1793. let lastCallPos = start.lastIndexOf("@");
  1794. start = content.value.slice(0, lastCallPos + 1);
  1795. if (e2 === "管理员") {
  1796. e2 = "Livid @Kai @Olivia @GordianZ @sparanoid";
  1797. }
  1798. if (e2 === "所有人") {
  1799. e2 = allReplyUsers.value.map((v, i) => {
  1800. if (i)
  1801. return "@" + v;
  1802. else
  1803. return v;
  1804. }).join(" ");
  1805. }
  1806. content.value = start + e2 + " " + end;
  1807. let moveCursorPos = start.length + e2.length + 1;
  1808. setTimeout(() => {
  1809. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  1810. checkHeight2();
  1811. });
  1812. eventBus.off(CMD.SET_CALL);
  1813. });
  1814. }
  1815. function onKeydown(e2) {
  1816. let code = e2.keyCode;
  1817. switch (code) {
  1818. case 8:
  1819. if (content.value === "@") {
  1820. off();
  1821. }
  1822. break;
  1823. case 37:
  1824. case 38:
  1825. case 39:
  1826. case 40:
  1827. setTimeout(() => onInput({ data: "" }), 100);
  1828. break;
  1829. case 27:
  1830. e2.preventDefault();
  1831. e2.stopPropagation();
  1832. e2.stopImmediatePropagation();
  1833. return false;
  1834. case 13:
  1835. if (e2.ctrlKey)
  1836. submit();
  1837. if (e2.metaKey)
  1838. submit();
  1839. break;
  1840. }
  1841. }
  1842. function onInput(e2) {
  1843. let cursorPos = txtRef.value.selectionStart;
  1844. if (!content.value)
  1845. return;
  1846. if (e2.data === " ") {
  1847. return off();
  1848. }
  1849. if (e2.data === "@") {
  1850. if (content.value.length !== 1) {
  1851. if (content.value[cursorPos - 2] === " " || content.value[cursorPos - 2] === "\n") {
  1852. return showCallPopover("");
  1853. }
  1854. } else {
  1855. return showCallPopover("");
  1856. }
  1857. off();
  1858. } else {
  1859. let judgeStr = content.value.slice(0, cursorPos);
  1860. let lastCallPos = judgeStr.lastIndexOf("@");
  1861. if (lastCallPos === -1) {
  1862. return off();
  1863. }
  1864. let callStr = judgeStr.slice(lastCallPos, cursorPos);
  1865. let hasSpace = callStr.includes(" ");
  1866. if (hasSpace) {
  1867. off();
  1868. } else {
  1869. if (lastCallPos === 0) {
  1870. return showCallPopover(callStr.replace("@", ""));
  1871. }
  1872. if (content.value.length !== 1) {
  1873. if (content.value[lastCallPos - 1] === " " || content.value[lastCallPos - 1] === "\n") {
  1874. return showCallPopover(callStr.replace("@", ""));
  1875. }
  1876. } else {
  1877. return showCallPopover(callStr.replace("@", ""));
  1878. }
  1879. off();
  1880. }
  1881. }
  1882. }
  1883. function onPaste(e2) {
  1884. const dataTransferItemList = e2.clipboardData.items;
  1885. const items = [].slice.call(dataTransferItemList).filter(function(item) {
  1886. return item.type.indexOf("image") !== -1;
  1887. });
  1888. if (items.length === 0) {
  1889. return;
  1890. }
  1891. const dataTransferItem = items[0];
  1892. const blob = dataTransferItem.getAsFile();
  1893. upload(blob);
  1894. }
  1895. function onBlur() {
  1896. document.removeEventListener("paste", onPaste);
  1897. isFocus.value = false;
  1898. }
  1899. function onFocusin() {
  1900. document.addEventListener("paste", onPaste);
  1901. }
  1902. vue.watch(() => show, (n2) => {
  1903. if (n2.value)
  1904. isShowEmoticons.value = false;
  1905. }, { deep: true });
  1906. vue.onMounted(() => {
  1907. $(`.${editorId.value}`).each(function() {
  1908. this.setAttribute("style", "height:" + this.scrollHeight + "px;overflow-y:hidden;");
  1909. }).on("input", function() {
  1910. this.style.height = 0;
  1911. this.style.height = this.scrollHeight + "px";
  1912. });
  1913. if (useType === "reply-comment") {
  1914. txtRef.value && txtRef.value.focus();
  1915. }
  1916. });
  1917. vue.onBeforeUnmount(() => {
  1918. $(`.${editorId.value}`).off();
  1919. });
  1920. return (_ctx, _cache) => {
  1921. return vue.openBlock(), vue.createElementBlock("div", {
  1922. class: vue.normalizeClass(["post-editor-wrapper", editorClass.value])
  1923. }, [
  1924. vue.withDirectives(vue.createElementVNode("textarea", {
  1925. class: vue.normalizeClass(["post-editor", editorId.value]),
  1926. ref_key: "txtRef",
  1927. ref: txtRef,
  1928. onFocus: _cache[0] || (_cache[0] = ($event) => vue.isRef(isFocus) ? isFocus.value = true : isFocus = true),
  1929. onBlur,
  1930. onFocusin,
  1931. placeholder: "请尽量让自己的回复能够对别人有帮助",
  1932. onInput,
  1933. onKeydown,
  1934. onDrop: drop,
  1935. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => content.value = $event)
  1936. }, null, 34), [
  1937. [vue.vModelText, content.value]
  1938. ]),
  1939. vue.createElementVNode("div", _hoisted_1$b, [
  1940. vue.createElementVNode("span", { innerHTML: cursorHtml.value }, null, 8, _hoisted_2$a),
  1941. vue.createElementVNode("span", {
  1942. class: "cursor",
  1943. ref_key: "cursorRef",
  1944. ref: cursorRef
  1945. }, "|", 512)
  1946. ]),
  1947. vue.createElementVNode("div", _hoisted_3$7, [
  1948. vue.createElementVNode("div", _hoisted_4$7, [
  1949. (vue.openBlock(), vue.createElementBlock("svg", {
  1950. onClick: showEmoticons,
  1951. width: "20",
  1952. height: "20",
  1953. viewBox: "0 0 48 48",
  1954. fill: "none",
  1955. xmlns: "http://www.w3.org/2000/svg"
  1956. }, _hoisted_9$5)),
  1957. vue.createElementVNode("div", _hoisted_10$4, [
  1958. vue.createElementVNode("input", {
  1959. type: "file",
  1960. accept: "image/*",
  1961. onChange: _cache[2] || (_cache[2] = (e2) => upload(e2.currentTarget.files[0]))
  1962. }, null, 32),
  1963. _hoisted_11$4
  1964. ]),
  1965. uploadLoading.value ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_12$4, "上传中.....")) : vue.createCommentVNode("", true)
  1966. ]),
  1967. vue.createElementVNode("div", _hoisted_13$4, [
  1968. vue.unref(useType) === "reply-comment" ? (vue.openBlock(), vue.createBlock(BaseButton, {
  1969. key: 0,
  1970. type: "link",
  1971. size: "small",
  1972. style: { "margin-right": "1rem", "cursor": "pointer" },
  1973. onClick: _cache[3] || (_cache[3] = ($event) => emits("close"))
  1974. }, {
  1975. default: vue.withCtx(() => [
  1976. vue.createTextVNode(" 关闭 ")
  1977. ]),
  1978. _: 1
  1979. })) : vue.createCommentVNode("", true),
  1980. vue.createVNode(BaseButton, {
  1981. size: "small",
  1982. disabled: disabled.value,
  1983. loading: loading.value,
  1984. onClick: submit
  1985. }, {
  1986. default: vue.withCtx(() => [
  1987. vue.createTextVNode("回复 ")
  1988. ]),
  1989. _: 1
  1990. }, 8, ["disabled", "loading"])
  1991. ])
  1992. ]),
  1993. vue.withDirectives(vue.createElementVNode("div", {
  1994. class: "emoticon-pack",
  1995. ref_key: "emoticonsRef",
  1996. ref: emoticonsRef
  1997. }, [
  1998. vue.createElementVNode("i", {
  1999. class: "fa fa-times",
  2000. "aria-hidden": "true",
  2001. onClick: _cache[4] || (_cache[4] = ($event) => isShowEmoticons.value = false)
  2002. }),
  2003. _hoisted_14$4,
  2004. vue.createElementVNode("div", _hoisted_15$4, [
  2005. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(classicsEmoticons, (item) => {
  2006. return vue.createElementVNode("img", {
  2007. src: item.high,
  2008. onClick: ($event) => {
  2009. insert(item.name);
  2010. isShowEmoticons.value = false;
  2011. }
  2012. }, null, 8, _hoisted_16$4);
  2013. }), 64))
  2014. ]),
  2015. vue.createElementVNode("div", _hoisted_17$3, [
  2016. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(emojiEmoticons, (item) => {
  2017. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  2018. vue.createElementVNode("div", _hoisted_18$3, vue.toDisplayString(item.title), 1),
  2019. vue.createElementVNode("div", _hoisted_19$2, [
  2020. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.list, (emoji) => {
  2021. return vue.openBlock(), vue.createElementBlock("span", {
  2022. onClick: ($event) => {
  2023. insert(emoji);
  2024. isShowEmoticons.value = false;
  2025. }
  2026. }, vue.toDisplayString(emoji), 9, _hoisted_20$2);
  2027. }), 256))
  2028. ])
  2029. ], 64);
  2030. }), 64))
  2031. ])
  2032. ], 512), [
  2033. [vue.vShow, isShowEmoticons.value]
  2034. ])
  2035. ], 2);
  2036. };
  2037. }
  2038. };
  2039. const PostEditor = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-fb753464"]]);
  2040. const _hoisted_1$a = {
  2041. key: 0,
  2042. class: "html-wrapper"
  2043. };
  2044. const _hoisted_2$9 = ["innerHTML"];
  2045. const checkHeight = 900;
  2046. const _sfc_main$a = {
  2047. __name: "BaseHtmlRender",
  2048. props: ["html"],
  2049. setup(__props) {
  2050. const config2 = vue.inject("config");
  2051. const props = __props;
  2052. const contentRef = vue.ref(null);
  2053. const mask = vue.ref(false);
  2054. const handOpen = vue.ref(false);
  2055. function mouseup(e2) {
  2056. if (!config2.value.base64)
  2057. return;
  2058. let selectionText = window.win().getSelection().toString();
  2059. if (selectionText) {
  2060. let r2 = selectionText.match(/([A-Za-z0-9+/=]+)/g);
  2061. if (r2) {
  2062. if (r2[0].length < 4)
  2063. return;
  2064. eventBus.emit(CMD.SHOW_TOOLTIP, { text: r2[0], e: e2 });
  2065. }
  2066. }
  2067. }
  2068. vue.watch(config2.value, (newVale) => {
  2069. if (!newVale.contentAutoCollapse) {
  2070. mask.value = false;
  2071. }
  2072. });
  2073. vue.watch([() => contentRef.value, () => props.html], () => {
  2074. if (!contentRef.value || !props.html)
  2075. return;
  2076. if (!config2.value.contentAutoCollapse)
  2077. return;
  2078. contentRef.value.querySelectorAll("img").forEach((item) => {
  2079. item.removeEventListener("load", checkContentHeight);
  2080. item.addEventListener("load", checkContentHeight);
  2081. });
  2082. checkContentHeight();
  2083. }, { immediate: true, flush: "post" });
  2084. function checkContentHeight() {
  2085. if (handOpen.value)
  2086. return;
  2087. let rect = contentRef.value.getBoundingClientRect();
  2088. mask.value = rect.height >= checkHeight;
  2089. }
  2090. return (_ctx, _cache) => {
  2091. return props.html ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$a, [
  2092. vue.createElementVNode("div", {
  2093. class: vue.normalizeClass({ mask: mask.value })
  2094. }, [
  2095. vue.createElementVNode("div", {
  2096. ref_key: "contentRef",
  2097. ref: contentRef,
  2098. innerHTML: props.html,
  2099. onMouseup: mouseup
  2100. }, null, 40, _hoisted_2$9)
  2101. ], 2),
  2102. mask.value ? (vue.openBlock(), vue.createElementBlock("div", {
  2103. key: 0,
  2104. class: "expand",
  2105. onClick: _cache[0] || (_cache[0] = ($event) => {
  2106. mask.value = false;
  2107. handOpen.value = true;
  2108. })
  2109. }, "展开")) : vue.createCommentVNode("", true)
  2110. ])) : vue.createCommentVNode("", true);
  2111. };
  2112. }
  2113. };
  2114. const BaseHtmlRender = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-2c9a538c"]]);
  2115. const _sfc_main$9 = {
  2116. name: "Comment",
  2117. components: { BaseHtmlRender, Author, PostEditor, Point },
  2118. inject: ["post", "postDetailWidth", "show", "isNight", "config"],
  2119. props: {
  2120. modelValue: {
  2121. reply_content: ""
  2122. },
  2123. type: {
  2124. type: String,
  2125. default() {
  2126. return "list";
  2127. }
  2128. }
  2129. },
  2130. data() {
  2131. return {
  2132. showOrigin: false,
  2133. edit: false,
  2134. ding: false,
  2135. expand: true,
  2136. expandWrong: false,
  2137. replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
  2138. cssStyle: null,
  2139. floor: this.modelValue.floor
  2140. };
  2141. },
  2142. watch: {
  2143. show(e2) {
  2144. if (e2) {
  2145. this.edit = false;
  2146. }
  2147. },
  2148. postDetailWidth(n2, o) {
  2149. this.checkIsTooLong(n2);
  2150. }
  2151. },
  2152. computed: {
  2153. CommentDisplayType() {
  2154. return CommentDisplayType;
  2155. },
  2156. myClass() {
  2157. return {
  2158. isOp: this.modelValue.isOp,
  2159. isSimple: this.config.viewType === "simple",
  2160. ding: this.ding,
  2161. isLevelOne: this.modelValue.level === 0,
  2162. ["c_" + this.floor]: this.type !== "top"
  2163. };
  2164. }
  2165. },
  2166. mounted() {
  2167. this.checkIsTooLong(this.postDetailWidth);
  2168. },
  2169. methods: {
  2170. checkIsTooLong(postDetailWidth) {
  2171. if (postDetailWidth !== 0) {
  2172. let rect = this.$refs.comment.getBoundingClientRect();
  2173. let ban = postDetailWidth / 2;
  2174. if (ban < rect.width && rect.width < ban + 25 && this.modelValue.children.length) {
  2175. this.expand = false;
  2176. let padding = 2;
  2177. this.cssStyle = {
  2178. padding: "1rem 0",
  2179. width: `calc(${postDetailWidth}px - ${padding}rem)`,
  2180. transform: `translateX(calc(${rect.width - postDetailWidth}px + ${padding}rem))`,
  2181. background: this.isNight ? "#18222d" : "white"
  2182. };
  2183. }
  2184. }
  2185. },
  2186. //高亮一下
  2187. showDing() {
  2188. this.ding = true;
  2189. setTimeout(() => {
  2190. this.ding = false;
  2191. }, 2e3);
  2192. },
  2193. hide() {
  2194. let url = `${window.baseUrl}/ignore/reply/${this.modelValue.id}?once=${this.post.once}`;
  2195. eventBus.emit(CMD.REMOVE, this.modelValue.floor);
  2196. $.post(url).then((res) => {
  2197. eventBus.emit(CMD.REFRESH_ONCE);
  2198. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "隐藏成功" });
  2199. }, (err) => {
  2200. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "隐藏成功,仅本次有效(接口调用失败!)" });
  2201. });
  2202. },
  2203. toggle() {
  2204. this.expand = !this.expand;
  2205. },
  2206. toggleContent() {
  2207. if (this.modelValue.level === 0 && this.modelValue.replyUsers.length === 0)
  2208. return;
  2209. this.showOrigin = !this.showOrigin;
  2210. }
  2211. }
  2212. };
  2213. const _withScopeId$8 = (n2) => (vue.pushScopeId("data-v-888958af"), n2 = n2(), vue.popScopeId(), n2);
  2214. const _hoisted_1$9 = ["data-floor"];
  2215. const _hoisted_2$8 = { class: "comment-content" };
  2216. const _hoisted_3$6 = { class: "right" };
  2217. const _hoisted_4$6 = { class: "w" };
  2218. const _hoisted_5$5 = {
  2219. key: 0,
  2220. class: "wrong-wrapper"
  2221. };
  2222. const _hoisted_6$5 = ["href"];
  2223. const _hoisted_7$4 = { class: "del-line" };
  2224. const _hoisted_8$4 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("i", {
  2225. class: "fa fa-question-circle-o wrong-icon",
  2226. "aria-hidden": "true"
  2227. }, null, -1));
  2228. const _hoisted_9$4 = {
  2229. key: 0,
  2230. class: "warning"
  2231. };
  2232. const _hoisted_10$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2233. const _hoisted_11$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2234. const _hoisted_12$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2235. const _hoisted_13$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2236. const _hoisted_14$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2237. const _hoisted_15$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("a", {
  2238. href: "https://github.com/zyronon/web-scripts/issues",
  2239. target: "_blank"
  2240. }, "这里", -1));
  2241. const _hoisted_16$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("p", null, "---原文---", -1));
  2242. const _hoisted_17$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("p", null, "-----------", -1));
  2243. const _hoisted_18$2 = { class: "simple-wrapper" };
  2244. function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
  2245. const _component_Author = vue.resolveComponent("Author");
  2246. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  2247. const _component_PostEditor = vue.resolveComponent("PostEditor");
  2248. const _component_Comment = vue.resolveComponent("Comment", true);
  2249. return vue.openBlock(), vue.createElementBlock("div", {
  2250. class: vue.normalizeClass(["comment", $options.myClass]),
  2251. ref: "comment",
  2252. "data-floor": $data.floor
  2253. }, [
  2254. vue.createVNode(_component_Author, {
  2255. modelValue: $data.expand,
  2256. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
  2257. comment: $props.modelValue,
  2258. onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
  2259. type: $props.type,
  2260. onHide: $options.hide
  2261. }, null, 8, ["modelValue", "comment", "type", "onHide"]),
  2262. $data.cssStyle && !$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  2263. key: 0,
  2264. class: "more ago",
  2265. onClick: _cache[2] || (_cache[2] = ($event) => $data.expand = !$data.expand)
  2266. }, " 由于嵌套回复层级太深,自动将后续回复隐藏 ")) : vue.createCommentVNode("", true),
  2267. $data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  2268. key: 1,
  2269. class: "comment-content-w",
  2270. style: vue.normalizeStyle($data.cssStyle)
  2271. }, [
  2272. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  2273. key: 0,
  2274. class: "more ago",
  2275. onClick: _cache[3] || (_cache[3] = ($event) => $data.expand = !$data.expand)
  2276. }, " 由于嵌套回复层级太深,自动将以下回复移至可见范围 ")) : vue.createCommentVNode("", true),
  2277. vue.createElementVNode("div", _hoisted_2$8, [
  2278. vue.createElementVNode("div", {
  2279. class: "left expand-line",
  2280. onClick: _cache[4] || (_cache[4] = (...args) => $options.toggle && $options.toggle(...args))
  2281. }),
  2282. vue.createElementVNode("div", _hoisted_3$6, [
  2283. vue.createElementVNode("div", _hoisted_4$6, [
  2284. $props.modelValue.isWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$5, [
  2285. vue.createElementVNode("span", {
  2286. onClick: _cache[5] || (_cache[5] = ($event) => $data.expandWrong = !$data.expandWrong),
  2287. title: "点击楼层号查看提示"
  2288. }, [
  2289. vue.createElementVNode("a", {
  2290. href: "/member/" + $props.modelValue.replyUsers[0]
  2291. }, "@" + vue.toDisplayString($props.modelValue.replyUsers[0]) + "  ", 9, _hoisted_6$5),
  2292. vue.createElementVNode("span", _hoisted_7$4, "#" + vue.toDisplayString($props.modelValue.replyFloor), 1),
  2293. _hoisted_8$4
  2294. ]),
  2295. $data.expandWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$4, [
  2296. vue.createTextVNode(" 这条回复似乎有点问题,指定的楼层号与@的人对应不上 "),
  2297. _hoisted_10$3,
  2298. vue.createTextVNode(" 原因可能有下面几种: "),
  2299. _hoisted_11$3,
  2300. vue.createTextVNode(" 一、屏蔽用户导致楼层塌陷:你屏蔽了A,自A以后的回复的楼层号都会减1 "),
  2301. _hoisted_12$3,
  2302. vue.createTextVNode(" 二、忽略回复导致楼层塌陷:原理同上 "),
  2303. _hoisted_13$3,
  2304. vue.createTextVNode(" 三、层主回复时指定错了楼层号(同一,层主屏蔽了别人,导致楼层塌陷) "),
  2305. _hoisted_14$3,
  2306. vue.createTextVNode(" 四、脚本解析错误,请在 "),
  2307. _hoisted_15$3,
  2308. vue.createTextVNode("反馈 ")
  2309. ])) : vue.createCommentVNode("", true)
  2310. ])) : vue.createCommentVNode("", true),
  2311. $options.config.commentDisplayType === $options.CommentDisplayType.FloorInFloorNoCallUser && this.type !== "top" ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  2312. $data.showOrigin ? (vue.openBlock(), vue.createElementBlock("div", {
  2313. key: 0,
  2314. onDblclick: _cache[6] || (_cache[6] = (...args) => $options.toggleContent && $options.toggleContent(...args))
  2315. }, [
  2316. _hoisted_16$3,
  2317. vue.createVNode(_component_BaseHtmlRender, {
  2318. class: "reply_content",
  2319. html: $props.modelValue.reply_content
  2320. }, null, 8, ["html"]),
  2321. _hoisted_17$2
  2322. ], 32)) : vue.createCommentVNode("", true),
  2323. vue.createVNode(_component_BaseHtmlRender, {
  2324. class: "reply_content",
  2325. onDblclick: $options.toggleContent,
  2326. html: $props.modelValue.hideCallUserReplyContent
  2327. }, null, 8, ["onDblclick", "html"])
  2328. ], 64)) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  2329. key: 2,
  2330. class: "reply_content",
  2331. html: $props.modelValue.reply_content
  2332. }, null, 8, ["html"])),
  2333. $data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
  2334. key: 3,
  2335. onClose: _cache[7] || (_cache[7] = ($event) => $data.edit = false),
  2336. replyInfo: $data.replyInfo,
  2337. replyUser: $props.modelValue.username,
  2338. replyFloor: $props.modelValue.floor
  2339. }, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true)
  2340. ]),
  2341. vue.createElementVNode("div", _hoisted_18$2, [
  2342. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index) => {
  2343. return vue.openBlock(), vue.createBlock(_component_Comment, {
  2344. modelValue: $props.modelValue.children[index],
  2345. "onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
  2346. key: index
  2347. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  2348. }), 128))
  2349. ])
  2350. ])
  2351. ]),
  2352. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  2353. key: 1,
  2354. class: "more ago",
  2355. onClick: _cache[8] || (_cache[8] = ($event) => $data.expand = !$data.expand)
  2356. }, " 由于嵌套回复层级太深,自动将以上回复移至可见范围 ")) : vue.createCommentVNode("", true)
  2357. ], 4)) : vue.createCommentVNode("", true)
  2358. ], 10, _hoisted_1$9);
  2359. }
  2360. const Comment = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$4], ["__scopeId", "data-v-888958af"]]);
  2361. const _sfc_main$8 = {
  2362. name: "Toolbar",
  2363. components: { BaseLoading },
  2364. inject: [
  2365. "isLogin",
  2366. "post",
  2367. "pageType"
  2368. ],
  2369. data() {
  2370. return {
  2371. timer: null,
  2372. loading: false,
  2373. loading2: false,
  2374. loading3: false
  2375. };
  2376. },
  2377. methods: {
  2378. checkIsLogin(emitName = "") {
  2379. if (!this.isLogin) {
  2380. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  2381. return false;
  2382. }
  2383. this.$emit(emitName);
  2384. return true;
  2385. },
  2386. getColor(val) {
  2387. return val ? "#ff4500" : "#929596";
  2388. },
  2389. getIsFull(val) {
  2390. return val ? "#ff4500" : "none";
  2391. },
  2392. tweet() {
  2393. if (!this.checkIsLogin())
  2394. return;
  2395. let username = window.user.username;
  2396. let url = `https://twitter.com/intent/tweet?url=${window.baseUrl}/t/${this.post.id}?r=${username}&related=v2ex&text=${this.post.title}`;
  2397. window.win().open(url, "_blank", "width=550,height=370");
  2398. },
  2399. report() {
  2400. if (!this.checkIsLogin())
  2401. return;
  2402. if (!this.isLogin)
  2403. return;
  2404. if (this.post.isReport)
  2405. return;
  2406. let username = window.user.username;
  2407. let url = `https://twitter.com/share?url=${window.baseUrl}/t/${this.post.id}?r=${username}&amp;related=v2ex&amp;hashtags=apple&amp;text=${this.post.title}`;
  2408. window.win().open(url, "_blank", "width=550,height=370");
  2409. },
  2410. async toggleIgnore() {
  2411. if (!this.checkIsLogin())
  2412. return;
  2413. let url = `${window.baseUrl}/${this.post.isIgnore ? "unignore" : "ignore"}/topic/${this.post.id}?once=${this.post.once}`;
  2414. if (this.pageType === PageType.Post) {
  2415. this.loading2 = true;
  2416. let apiRes = await window.win().fetch(url);
  2417. if (apiRes.redirected) {
  2418. if (!this.post.isIgnore) {
  2419. window.win().location = window.baseUrl;
  2420. }
  2421. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  2422. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  2423. } else {
  2424. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略失败" });
  2425. }
  2426. this.loading2 = false;
  2427. } else {
  2428. if (this.post.isIgnore) {
  2429. this.loading2 = true;
  2430. } else {
  2431. eventBus.emit(CMD.IGNORE);
  2432. }
  2433. let apiRes = await window.win().fetch(url);
  2434. if (apiRes.redirected) {
  2435. if (this.post.isIgnore) {
  2436. eventBus.emit(CMD.REFRESH_ONCE);
  2437. }
  2438. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  2439. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  2440. } else {
  2441. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略成功,仅本次有效(接口调用失败!)" });
  2442. }
  2443. this.loading2 = false;
  2444. }
  2445. },
  2446. async toggleFavorite() {
  2447. if (!this.post.isFavorite && config.collectBrowserNotice) {
  2448. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "别忘记按Command/Cmd/CTRL + D添加到书签哦" });
  2449. }
  2450. if (!this.checkIsLogin())
  2451. return;
  2452. this.loading = true;
  2453. let url = `${window.baseUrl}/${this.post.isFavorite ? "unfavorite" : "favorite"}/topic/${this.post.id}?once=${this.post.once}`;
  2454. let apiRes = await window.win().fetch(url);
  2455. this.loading = false;
  2456. if (apiRes.redirected) {
  2457. let htmlText = await apiRes.text();
  2458. if (htmlText.search(this.post.isFavorite ? "加入收藏" : "取消收藏")) {
  2459. eventBus.emit(CMD.MERGE, { collectCount: this.post.isFavorite ? this.post.collectCount - 1 : this.post.collectCount + 1 });
  2460. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isFavorite ? "取消成功" : "收藏成功" });
  2461. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  2462. eventBus.emit(CMD.MERGE, { isFavorite: !this.post.isFavorite });
  2463. return;
  2464. }
  2465. }
  2466. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败" });
  2467. }
  2468. }
  2469. };
  2470. const _withScopeId$7 = (n2) => (vue.pushScopeId("data-v-c98b8c46"), n2 = n2(), vue.popScopeId(), n2);
  2471. const _hoisted_1$8 = { class: "toolbar" };
  2472. const _hoisted_2$7 = /* @__PURE__ */ vue.createStaticVNode('<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-c98b8c46><path d="M4 6H44V36H29L24 41L19 36H4V6Z" fill="none" stroke="#929596" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-c98b8c46></path><path d="M23 21H25.0025" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c98b8c46></path><path d="M33.001 21H34.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c98b8c46></path><path d="M13.001 21H14.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-c98b8c46></path></svg><span data-v-c98b8c46>回复</span>', 2);
  2473. const _hoisted_4$5 = [
  2474. _hoisted_2$7
  2475. ];
  2476. const _hoisted_5$4 = {
  2477. key: 1,
  2478. viewBox: "0 0 48 48",
  2479. fill: "none",
  2480. xmlns: "http://www.w3.org/2000/svg"
  2481. };
  2482. const _hoisted_6$4 = ["fill", "stroke"];
  2483. const _hoisted_7$3 = {
  2484. key: 1,
  2485. class: "tool no-hover"
  2486. };
  2487. const _hoisted_8$3 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2488. viewBox: "0 0 48 48",
  2489. fill: "none",
  2490. xmlns: "http://www.w3.org/2000/svg"
  2491. }, [
  2492. /* @__PURE__ */ vue.createElementVNode("path", {
  2493. d: "M28 6H42V20",
  2494. stroke: "#929596",
  2495. "stroke-width": "2",
  2496. "stroke-linecap": "round",
  2497. "stroke-linejoin": "round"
  2498. }),
  2499. /* @__PURE__ */ vue.createElementVNode("path", {
  2500. d: "M42 29.4737V39C42 40.6569 40.6569 42 39 42H9C7.34315 42 6 40.6569 6 39V9C6 7.34315 7.34315 6 9 6L18 6",
  2501. stroke: "#929596",
  2502. "stroke-width": "2",
  2503. "stroke-linecap": "round",
  2504. "stroke-linejoin": "round"
  2505. }),
  2506. /* @__PURE__ */ vue.createElementVNode("path", {
  2507. d: "M25.7998 22.1999L41.0998 6.8999",
  2508. stroke: "#929596",
  2509. "stroke-width": "2",
  2510. "stroke-linecap": "round",
  2511. "stroke-linejoin": "round"
  2512. })
  2513. ], -1));
  2514. const _hoisted_9$3 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("span", null, "Tweet", -1));
  2515. const _hoisted_10$2 = [
  2516. _hoisted_8$3,
  2517. _hoisted_9$3
  2518. ];
  2519. const _hoisted_11$2 = {
  2520. key: 1,
  2521. viewBox: "0 0 48 48",
  2522. fill: "none",
  2523. xmlns: "http://www.w3.org/2000/svg"
  2524. };
  2525. const _hoisted_12$2 = ["fill", "stroke"];
  2526. const _hoisted_13$2 = ["fill", "stroke"];
  2527. const _hoisted_14$2 = ["fill", "stroke"];
  2528. const _hoisted_15$2 = {
  2529. key: 1,
  2530. width: "19",
  2531. height: "19",
  2532. viewBox: "0 0 48 48",
  2533. fill: "none",
  2534. xmlns: "http://www.w3.org/2000/svg"
  2535. };
  2536. const _hoisted_16$2 = /* @__PURE__ */ vue.createStaticVNode('<path d="M36 35H12V21C12 14.3726 17.3726 9 24 9C30.6274 9 36 14.3726 36 21V35Z" fill="#929596" stroke="#929596" stroke-width="4" stroke-linejoin="round" data-v-c98b8c46></path><path d="M8 42H40" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-c98b8c46></path><path d="M4 13L7 14" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-c98b8c46></path><path d="M13 3.9999L14 6.9999" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-c98b8c46></path><path d="M10.0001 9.99989L7.00009 6.99989" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-c98b8c46></path>', 5);
  2537. const _hoisted_21$2 = [
  2538. _hoisted_16$2
  2539. ];
  2540. function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
  2541. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  2542. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
  2543. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true),
  2544. vue.createElementVNode("div", {
  2545. class: "tool",
  2546. onClick: _cache[0] || (_cache[0] = ($event) => $options.checkIsLogin("reply"))
  2547. }, _hoisted_4$5),
  2548. $options.post.once ? (vue.openBlock(), vue.createElementBlock("div", {
  2549. key: 0,
  2550. class: vue.normalizeClass(["tool", { disabled: $data.loading }]),
  2551. onClick: _cache[1] || (_cache[1] = (...args) => $options.toggleFavorite && $options.toggleFavorite(...args))
  2552. }, [
  2553. $data.loading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  2554. key: 0,
  2555. size: "small"
  2556. })) : (vue.openBlock(), vue.createElementBlock("svg", _hoisted_5$4, [
  2557. vue.createElementVNode("path", {
  2558. d: "M23.9986 5L17.8856 17.4776L4 19.4911L14.0589 29.3251L11.6544 43L23.9986 36.4192L36.3454 43L33.9586 29.3251L44 19.4911L30.1913 17.4776L23.9986 5Z",
  2559. fill: $options.getIsFull($options.post.isFavorite),
  2560. stroke: $options.getColor($options.post.isFavorite),
  2561. "stroke-width": "2",
  2562. "stroke-linejoin": "round"
  2563. }, null, 8, _hoisted_6$4)
  2564. ])),
  2565. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isFavorite ? "取消收藏" : "加入收藏"), 1)
  2566. ], 2)) : vue.createCommentVNode("", true),
  2567. $options.post.once && $options.post.collectCount !== 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7$3, [
  2568. vue.createElementVNode("span", null, vue.toDisplayString($options.post.collectCount + "人收藏"), 1)
  2569. ])) : vue.createCommentVNode("", true),
  2570. vue.createElementVNode("div", {
  2571. class: "tool",
  2572. onClick: _cache[2] || (_cache[2] = (...args) => $options.tweet && $options.tweet(...args))
  2573. }, _hoisted_10$2),
  2574. $options.post.once ? (vue.openBlock(), vue.createElementBlock("div", {
  2575. key: 2,
  2576. class: vue.normalizeClass(["tool", { "disabled": $data.loading2 }]),
  2577. onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleIgnore && $options.toggleIgnore(...args))
  2578. }, [
  2579. $data.loading2 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  2580. key: 0,
  2581. size: "small"
  2582. })) : (vue.openBlock(), vue.createElementBlock("svg", _hoisted_11$2, [
  2583. vue.createElementVNode("path", {
  2584. fill: $options.getIsFull($options.post.isIgnore),
  2585. stroke: $options.getColor($options.post.isIgnore),
  2586. d: "M9.85786 18C6.23858 21 4 24 4 24C4 24 12.9543 36 24 36C25.3699 36 26.7076 35.8154 28 35.4921M20.0318 12.5C21.3144 12.1816 22.6414 12 24 12C35.0457 12 44 24 44 24C44 24 41.7614 27 38.1421 30",
  2587. "stroke-width": "2",
  2588. "stroke-linecap": "round",
  2589. "stroke-linejoin": "round"
  2590. }, null, 8, _hoisted_12$2),
  2591. vue.createElementVNode("path", {
  2592. fill: $options.getIsFull($options.post.isIgnore),
  2593. d: "M20.3142 20.6211C19.4981 21.5109 19 22.6972 19 23.9998C19 26.7612 21.2386 28.9998 24 28.9998C25.3627 28.9998 26.5981 28.4546 27.5 27.5705",
  2594. stroke: $options.getColor($options.post.isIgnore),
  2595. "stroke-width": "2",
  2596. "stroke-linecap": "round",
  2597. "stroke-linejoin": "round"
  2598. }, null, 8, _hoisted_13$2),
  2599. vue.createElementVNode("path", {
  2600. d: "M42 42L6 6",
  2601. fill: $options.getIsFull($options.post.isIgnore),
  2602. stroke: $options.getColor($options.post.isIgnore),
  2603. "stroke-width": "2",
  2604. "stroke-linecap": "round",
  2605. "stroke-linejoin": "round"
  2606. }, null, 8, _hoisted_14$2)
  2607. ])),
  2608. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isIgnore ? "取消忽略" : "忽略主题"), 1)
  2609. ], 2)) : vue.createCommentVNode("", true),
  2610. $options.post.once && $options.isLogin && false ? (vue.openBlock(), vue.createElementBlock("div", {
  2611. key: 3,
  2612. class: vue.normalizeClass(["tool", { "disabled": $data.loading3, "no-hover": $options.post.isLogin }]),
  2613. onClick: _cache[4] || (_cache[4] = (...args) => $options.report && $options.report(...args))
  2614. }, [
  2615. $data.loading3 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  2616. key: 0,
  2617. size: "small"
  2618. })) : (vue.openBlock(), vue.createElementBlock("svg", _hoisted_15$2, _hoisted_21$2)),
  2619. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isReport ? "你已对本主题进行了报告" : "报告这个主题"), 1)
  2620. ], 2)) : vue.createCommentVNode("", true)
  2621. ]);
  2622. }
  2623. const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$3], ["__scopeId", "data-v-c98b8c46"]]);
  2624. const _withScopeId$6 = (n2) => (vue.pushScopeId("data-v-953d8ab1"), n2 = n2(), vue.popScopeId(), n2);
  2625. const _hoisted_1$7 = ["href"];
  2626. const _hoisted_2$6 = ["src"];
  2627. const _hoisted_3$5 = { class: "texts" };
  2628. const _hoisted_4$4 = {
  2629. key: 0,
  2630. class: "point"
  2631. };
  2632. const _hoisted_5$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2633. width: "19",
  2634. height: "19",
  2635. viewBox: "0 0 48 48",
  2636. fill: "none"
  2637. }, [
  2638. /* @__PURE__ */ vue.createElementVNode("path", {
  2639. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  2640. fill: "#E02A2A",
  2641. stroke: "#E02A2A",
  2642. "stroke-width": "2",
  2643. "stroke-linecap": "round",
  2644. "stroke-linejoin": "round"
  2645. })
  2646. ], -1));
  2647. const _hoisted_6$3 = { class: "link-num" };
  2648. const _hoisted_7$2 = { class: "my-tag" };
  2649. const _hoisted_8$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  2650. const _hoisted_9$2 = {
  2651. key: 2,
  2652. class: "ago"
  2653. };
  2654. const _hoisted_10$1 = {
  2655. key: 3,
  2656. class: "mod"
  2657. };
  2658. const _hoisted_11$1 = {
  2659. key: 4,
  2660. class: "owner"
  2661. };
  2662. const _hoisted_12$1 = ["href"];
  2663. const _hoisted_13$1 = {
  2664. key: 5,
  2665. class: "owner"
  2666. };
  2667. const _hoisted_14$1 = {
  2668. key: 6,
  2669. class: "mod"
  2670. };
  2671. const _hoisted_15$1 = {
  2672. key: 7,
  2673. class: "ago"
  2674. };
  2675. const _hoisted_16$1 = { class: "my-tag" };
  2676. const _hoisted_17$1 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  2677. const _hoisted_18$1 = {
  2678. key: 9,
  2679. class: "point"
  2680. };
  2681. const _hoisted_19$1 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2682. width: "19",
  2683. height: "19",
  2684. viewBox: "0 0 48 48",
  2685. fill: "none"
  2686. }, [
  2687. /* @__PURE__ */ vue.createElementVNode("path", {
  2688. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  2689. fill: "#E02A2A",
  2690. stroke: "#E02A2A",
  2691. "stroke-width": "2",
  2692. "stroke-linecap": "round",
  2693. "stroke-linejoin": "round"
  2694. })
  2695. ], -1));
  2696. const _hoisted_20$1 = { class: "link-num" };
  2697. const _hoisted_21$1 = ["href"];
  2698. const _hoisted_22$1 = ["src"];
  2699. const _hoisted_23$1 = { class: "Author-right" };
  2700. const _hoisted_24$1 = { class: "floor" };
  2701. const _hoisted_25$1 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  2702. const _hoisted_26$1 = [
  2703. _hoisted_25$1
  2704. ];
  2705. const _sfc_main$7 = {
  2706. __name: "SingleComment",
  2707. props: {
  2708. comment: {
  2709. reply_content: ""
  2710. },
  2711. isRight: {
  2712. type: Boolean,
  2713. default() {
  2714. return false;
  2715. }
  2716. }
  2717. },
  2718. setup(__props) {
  2719. const config2 = vue.inject("config");
  2720. const isLogin = vue.inject("isLogin");
  2721. const tags = vue.inject("tags");
  2722. const props = __props;
  2723. const myTags = vue.computed(() => {
  2724. return tags[props.comment.username] ?? [];
  2725. });
  2726. function jump() {
  2727. eventBus.emit(CMD.JUMP, props.comment.floor);
  2728. }
  2729. return (_ctx, _cache) => {
  2730. return vue.openBlock(), vue.createElementBlock("div", {
  2731. class: vue.normalizeClass(["comment", { isSimple: vue.unref(config2).viewType === "simple" }]),
  2732. ref: "comment"
  2733. }, [
  2734. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  2735. key: 0,
  2736. class: "avatar",
  2737. href: `/member/${__props.comment.username}`
  2738. }, [
  2739. vue.createElementVNode("img", {
  2740. src: __props.comment.avatar,
  2741. alt: ""
  2742. }, null, 8, _hoisted_2$6)
  2743. ], 8, _hoisted_1$7)) : vue.createCommentVNode("", true),
  2744. vue.createElementVNode("div", {
  2745. class: vue.normalizeClass(["comment-body", { isRight: __props.isRight }])
  2746. }, [
  2747. vue.createElementVNode("div", _hoisted_3$5, [
  2748. __props.comment.thankCount && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, [
  2749. _hoisted_5$3,
  2750. vue.createElementVNode("div", _hoisted_6$3, vue.toDisplayString(__props.comment.thankCount), 1)
  2751. ])) : vue.createCommentVNode("", true),
  2752. vue.unref(isLogin) && vue.unref(config2).openTag && __props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(myTags.value, (i) => {
  2753. return vue.openBlock(), vue.createElementBlock("span", _hoisted_7$2, [
  2754. _hoisted_8$2,
  2755. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  2756. ]);
  2757. }), 256)) : vue.createCommentVNode("", true),
  2758. __props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_9$2, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  2759. __props.comment.isMod && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$1, "MOD")) : vue.createCommentVNode("", true),
  2760. __props.comment.isOp && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$1, "OP")) : vue.createCommentVNode("", true),
  2761. vue.createElementVNode("a", {
  2762. href: `/member/${__props.comment.username}`,
  2763. class: "username"
  2764. }, vue.toDisplayString(__props.comment.username), 9, _hoisted_12$1),
  2765. __props.comment.isOp && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$1, "OP")) : vue.createCommentVNode("", true),
  2766. __props.comment.isMod && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$1, "MOD")) : vue.createCommentVNode("", true),
  2767. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_15$1, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  2768. vue.unref(isLogin) && vue.unref(config2).openTag && !__props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 8 }, vue.renderList(myTags.value, (i) => {
  2769. return vue.openBlock(), vue.createElementBlock("span", _hoisted_16$1, [
  2770. _hoisted_17$1,
  2771. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  2772. ]);
  2773. }), 256)) : vue.createCommentVNode("", true),
  2774. __props.comment.thankCount && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18$1, [
  2775. _hoisted_19$1,
  2776. vue.createElementVNode("div", _hoisted_20$1, vue.toDisplayString(__props.comment.thankCount), 1)
  2777. ])) : vue.createCommentVNode("", true)
  2778. ]),
  2779. vue.createVNode(BaseHtmlRender, {
  2780. class: "reply_content",
  2781. html: __props.comment.reply_content
  2782. }, null, 8, ["html"])
  2783. ], 2),
  2784. __props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  2785. key: 1,
  2786. class: "avatar",
  2787. href: `/member/${__props.comment.username}`
  2788. }, [
  2789. vue.createElementVNode("img", {
  2790. src: __props.comment.avatar,
  2791. alt: ""
  2792. }, null, 8, _hoisted_22$1)
  2793. ], 8, _hoisted_21$1)) : vue.createCommentVNode("", true),
  2794. vue.createElementVNode("div", _hoisted_23$1, [
  2795. vue.createElementVNode("div", _hoisted_24$1, vue.toDisplayString(__props.comment.floor), 1),
  2796. vue.createElementVNode("div", {
  2797. class: "tool jump",
  2798. onClick: jump
  2799. }, _hoisted_26$1)
  2800. ])
  2801. ], 2);
  2802. };
  2803. }
  2804. };
  2805. const SingleComment = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-953d8ab1"]]);
  2806. function debounce(fn, delay, scope) {
  2807. let timer = null;
  2808. return function() {
  2809. let context = scope || this, args = arguments;
  2810. clearTimeout(timer);
  2811. timer = setTimeout(function() {
  2812. fn.apply(context, args);
  2813. timer = null;
  2814. }, delay);
  2815. };
  2816. }
  2817. const _sfc_main$6 = {
  2818. name: "detail",
  2819. components: {
  2820. BaseButton,
  2821. SingleComment,
  2822. PopConfirm,
  2823. Comment,
  2824. PostEditor,
  2825. Point,
  2826. Toolbar,
  2827. BaseHtmlRender,
  2828. Tooltip,
  2829. BaseLoading
  2830. },
  2831. inject: ["allReplyUsers", "post", "isMobile", "tags", "isLogin", "config", "pageType", "isNight"],
  2832. provide() {
  2833. return {
  2834. postDetailWidth: vue.computed(() => this.postDetailWidth)
  2835. };
  2836. },
  2837. props: {
  2838. modelValue: {
  2839. type: Boolean,
  2840. default() {
  2841. return false;
  2842. }
  2843. },
  2844. loading: {
  2845. type: Boolean,
  2846. default() {
  2847. return false;
  2848. }
  2849. },
  2850. refreshLoading: {
  2851. type: Boolean,
  2852. default() {
  2853. return false;
  2854. }
  2855. },
  2856. displayType: CommentDisplayType.FloorInFloorNoCallUser
  2857. },
  2858. data() {
  2859. return {
  2860. isSticky: false,
  2861. selectCallIndex: 0,
  2862. postDetailWidth: 0,
  2863. showCallList: false,
  2864. showRelationReply: false,
  2865. replyText: "",
  2866. callStyle: {
  2867. top: 0,
  2868. left: 0
  2869. },
  2870. targetUser: {
  2871. left: [],
  2872. right: "",
  2873. rightFloor: -1
  2874. },
  2875. debounceScroll: () => {
  2876. },
  2877. read: {
  2878. floor: 0,
  2879. total: 0
  2880. },
  2881. currentFloor: "",
  2882. showOpTag: false
  2883. };
  2884. },
  2885. computed: {
  2886. isMy() {
  2887. return this.post.member.username === window.user.username;
  2888. },
  2889. myTags() {
  2890. return this.tags[this.post.member.username] ?? [];
  2891. },
  2892. CommentDisplayType() {
  2893. return CommentDisplayType;
  2894. },
  2895. isPost() {
  2896. return this.pageType === PageType.Post;
  2897. },
  2898. filterCallList() {
  2899. if (this.showCallList) {
  2900. let list = ["管理员", "所有人"].concat(this.allReplyUsers);
  2901. if (this.replyText)
  2902. return list.filter((i) => i.search(this.replyText) > -1);
  2903. return list;
  2904. }
  2905. return [];
  2906. },
  2907. topReply() {
  2908. return this.post.replyList.filter((v) => v.thankCount >= this.config.topReplyLoveMinCount).sort((a, b) => b.thankCount - a.thankCount).slice(0, this.config.topReplyCount);
  2909. },
  2910. replyList() {
  2911. console.log("this.post.nestedReplies", this.post.nestedReplies);
  2912. if ([CommentDisplayType.FloorInFloor, CommentDisplayType.FloorInFloorNoCallUser].includes(this.displayType))
  2913. return this.post.nestedReplies;
  2914. if (this.displayType === CommentDisplayType.Like) {
  2915. return window.clone(this.post.nestedReplies).sort((a, b) => b.thankCount - a.thankCount);
  2916. }
  2917. if (this.displayType === CommentDisplayType.V2exOrigin)
  2918. return this.post.replyList;
  2919. if (this.displayType === CommentDisplayType.FloorInFloorNested)
  2920. return this.post.nestedRedundReplies;
  2921. if (this.displayType === CommentDisplayType.OnlyOp)
  2922. return this.post.replyList.filter((v) => {
  2923. var _a;
  2924. return v.username === ((_a = this.post.member) == null ? void 0 : _a.username);
  2925. });
  2926. return [];
  2927. },
  2928. //关联回复
  2929. relationReply() {
  2930. if (this.targetUser.left.length && this.targetUser.right) {
  2931. return this.post.replyList.filter((v) => {
  2932. if (this.targetUser.left.includes(v.username)) {
  2933. if (v.floor > this.targetUser.rightFloor) {
  2934. if (v.replyUsers.includes(this.targetUser.right)) {
  2935. return true;
  2936. }
  2937. } else {
  2938. return true;
  2939. }
  2940. }
  2941. if (v.username === this.targetUser.right) {
  2942. for (let i = 0; i < this.targetUser.left.length; i++) {
  2943. if (v.replyUsers.includes(this.targetUser.left[i])) {
  2944. return true;
  2945. }
  2946. }
  2947. }
  2948. });
  2949. }
  2950. return [];
  2951. }
  2952. },
  2953. watch: {
  2954. "post.id"(n2, o) {
  2955. if (this.$refs["post-editor"]) {
  2956. this.$refs["post-editor"].content = "";
  2957. vue.nextTick(() => {
  2958. var _a, _b;
  2959. (_b = (_a = this.$refs) == null ? void 0 : _a.detail) == null ? void 0 : _b.scrollTo({ top: 0 });
  2960. });
  2961. }
  2962. },
  2963. "post.headerTemplate"(n2, o) {
  2964. let mountEl = document.querySelector(".main-wrapper .post-wrapper .html-wrapper .header");
  2965. if (mountEl) {
  2966. this.showOpTag = true;
  2967. }
  2968. },
  2969. modelValue: {
  2970. handler(newVal) {
  2971. if (this.isPost) {
  2972. return;
  2973. }
  2974. if (newVal) {
  2975. document.body.style.overflow = "hidden";
  2976. if (!window.history.state) {
  2977. window.history.pushState({}, 0, this.post.url);
  2978. }
  2979. this.read = this.post.read;
  2980. this.currentFloor = "";
  2981. vue.nextTick(() => {
  2982. var _a, _b;
  2983. window.document.title = this.post.title ?? "V2EX";
  2984. (_b = (_a = this.$refs) == null ? void 0 : _a.main) == null ? void 0 : _b.focus();
  2985. });
  2986. } else {
  2987. this.$emit("saveReadList");
  2988. document.body.style.overflow = "unset";
  2989. window.document.title = "V2EX";
  2990. this.isSticky = false;
  2991. this.showRelationReply = false;
  2992. if (window.history.state) {
  2993. window.history.back();
  2994. }
  2995. }
  2996. }
  2997. }
  2998. },
  2999. mounted() {
  3000. setTimeout(() => {
  3001. var _a;
  3002. this.postDetailWidth = ((_a = this.$refs.mainWrapper) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
  3003. });
  3004. this.debounceScroll = debounce(this.scroll, 300, false);
  3005. if (this.isLogin) {
  3006. const observer = new IntersectionObserver(
  3007. ([e2]) => e2.target.toggleAttribute("stuck", e2.intersectionRatio < 1),
  3008. { threshold: [1] }
  3009. );
  3010. observer.observe(this.$refs.replyBox);
  3011. window.addEventListener("keydown", this.onKeyDown);
  3012. }
  3013. eventBus.on(CMD.SHOW_CALL, (val) => {
  3014. if (val.show) {
  3015. this.showCallList = true;
  3016. this.replyText = val.text;
  3017. if (this.isPost) {
  3018. this.callStyle.top = val.top + $(window.win()).scrollTop() + -40 + "px";
  3019. } else {
  3020. this.callStyle.top = val.top + $(".post-detail").scrollTop() + 15 + "px";
  3021. }
  3022. this.callStyle.left = val.left - $(".main")[0].getBoundingClientRect().left + 10 + "px";
  3023. if (this.selectCallIndex >= this.filterCallList.length) {
  3024. this.selectCallIndex = 0;
  3025. }
  3026. } else {
  3027. this.replyText = "";
  3028. this.showCallList = false;
  3029. this.selectCallIndex = 0;
  3030. }
  3031. });
  3032. eventBus.on(CMD.RELATION_REPLY, (val) => {
  3033. this.targetUser = val;
  3034. this.showRelationReply = true;
  3035. });
  3036. eventBus.on(CMD.JUMP, this.jump);
  3037. if (this.isPost) {
  3038. window.addEventListener("scroll", this.debounceScroll);
  3039. }
  3040. },
  3041. beforeUnmount() {
  3042. window.removeEventListener("keydown", this.onKeyDown);
  3043. eventBus.off(CMD.SHOW_CALL);
  3044. },
  3045. methods: {
  3046. addTag() {
  3047. eventBus.emit(CMD.ADD_TAG, this.post.member.username);
  3048. },
  3049. removeTag(tag) {
  3050. eventBus.emit(CMD.REMOVE_TAG, { username: this.post.member.username, tag });
  3051. },
  3052. scroll() {
  3053. if (!this.config.rememberLastReadFloor)
  3054. return;
  3055. let height = window.innerHeight * 0.3;
  3056. let comments = $(".comments .comment");
  3057. let forCount = 0;
  3058. for (let i = 0; i < comments.length; i++) {
  3059. forCount++;
  3060. let ins = comments[i];
  3061. let rect = ins.getBoundingClientRect();
  3062. if (rect.top > height) {
  3063. let lastReadFloor = Number(ins.dataset["floor"]);
  3064. console.log("当前阅读楼层", lastReadFloor);
  3065. eventBus.emit(CMD.ADD_READ, {
  3066. floor: lastReadFloor > 3 ? lastReadFloor : 0,
  3067. total: this.post.replyList.length
  3068. });
  3069. if (lastReadFloor > 3) {
  3070. this.read.floor = 0;
  3071. }
  3072. break;
  3073. }
  3074. }
  3075. if (forCount === comments.length) {
  3076. console.log("看到最后了");
  3077. eventBus.emit(CMD.ADD_READ, {
  3078. floor: forCount,
  3079. total: this.post.replyList.length
  3080. });
  3081. }
  3082. },
  3083. stop(e2) {
  3084. },
  3085. jump(floor) {
  3086. let lastItem = this.replyList[this.replyList.length - 1];
  3087. if (floor === "") {
  3088. floor = lastItem.floor;
  3089. } else {
  3090. try {
  3091. floor = Number(floor);
  3092. } catch (e2) {
  3093. floor = lastItem.floor;
  3094. }
  3095. if (floor === 0) {
  3096. floor = 1;
  3097. }
  3098. if (floor > lastItem.floor)
  3099. floor = lastItem.floor;
  3100. }
  3101. if (!this.post.replyList.length) {
  3102. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "没有回复可跳转!" });
  3103. this.read.floor = 0;
  3104. return;
  3105. }
  3106. if (floor > this.post.replyList.length) {
  3107. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  3108. this.read.floor = 0;
  3109. return;
  3110. }
  3111. let comment = $(`.c_${floor}`);
  3112. if (!comment.length) {
  3113. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  3114. this.read.floor = 0;
  3115. return;
  3116. }
  3117. comment[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
  3118. comment.addClass("ding");
  3119. this.read.floor = 0;
  3120. this.currentFloor = floor + 1;
  3121. setTimeout(() => {
  3122. comment.removeClass("ding");
  3123. }, 2e3);
  3124. },
  3125. jumpLastRead(floor) {
  3126. if (this.config.autoJumpLastReadFloor) {
  3127. if (!floor)
  3128. return;
  3129. setTimeout(() => {
  3130. console.log("上次跳转", floor);
  3131. this.jump(floor);
  3132. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "已跳转到上次阅读位置" });
  3133. }, 300);
  3134. }
  3135. },
  3136. collapseTopReplyList() {
  3137. $(this.$refs.topReply).slideToggle("fast");
  3138. },
  3139. goBottom() {
  3140. this.isSticky = false;
  3141. setTimeout(() => {
  3142. if (this.isPost) {
  3143. let body = $("body , html");
  3144. let scrollHeight = body.prop("scrollHeight");
  3145. body.animate({ scrollTop: scrollHeight - 850 }, 300);
  3146. } else {
  3147. this.$refs.detail.scrollTo({ top: this.$refs.detail.scrollHeight, behavior: "smooth" });
  3148. }
  3149. });
  3150. },
  3151. close(from) {
  3152. if (this.isPost)
  3153. return;
  3154. if (from === "space") {
  3155. if (this.config.closePostDetailBySpace) {
  3156. this.$emit("update:modelValue", false);
  3157. }
  3158. } else {
  3159. this.$emit("update:modelValue", false);
  3160. }
  3161. },
  3162. setCall(e2) {
  3163. eventBus.emit(CMD.SET_CALL, e2);
  3164. this.showCallList = false;
  3165. },
  3166. onKeyDown(e2) {
  3167. if (!this.modelValue)
  3168. return;
  3169. if (!this.showCallList)
  3170. return;
  3171. let length = this.filterCallList.slice(0, 10).length;
  3172. if (e2.keyCode === 13) {
  3173. this.setCall(this.filterCallList[this.selectCallIndex]);
  3174. e2.preventDefault();
  3175. }
  3176. if (e2.keyCode === 38) {
  3177. this.selectCallIndex--;
  3178. if (this.selectCallIndex < 0) {
  3179. this.selectCallIndex = length - 1;
  3180. }
  3181. e2.preventDefault();
  3182. }
  3183. if (e2.keyCode === 40) {
  3184. this.selectCallIndex++;
  3185. if (this.selectCallIndex > length - 1) {
  3186. this.selectCallIndex = 0;
  3187. }
  3188. e2.preventDefault();
  3189. }
  3190. },
  3191. changeOption(item) {
  3192. this.$emit("update:displayType", item);
  3193. },
  3194. addThank() {
  3195. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "add" });
  3196. },
  3197. recallThank() {
  3198. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "recall" });
  3199. },
  3200. scrollTop() {
  3201. if (this.isPost) {
  3202. $("body , html").animate({ scrollTop: 0 }, 300);
  3203. } else {
  3204. this.$refs.detail.scrollTo({ top: 0, behavior: "smooth" });
  3205. }
  3206. }
  3207. }
  3208. };
  3209. const _withScopeId$5 = (n2) => (vue.pushScopeId("data-v-7f8ab1e3"), n2 = n2(), vue.popScopeId(), n2);
  3210. const _hoisted_1$6 = { class: "my-box post-wrapper" };
  3211. const _hoisted_2$5 = { class: "header" };
  3212. const _hoisted_3$4 = { class: "fr" };
  3213. const _hoisted_4$3 = ["href"];
  3214. const _hoisted_5$2 = ["src", "alt"];
  3215. const _hoisted_6$2 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("a", { href: "/" }, "V2EX", -1));
  3216. const _hoisted_7$1 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "chevron" }, "  ›  ", -1));
  3217. const _hoisted_8$1 = ["href"];
  3218. const _hoisted_9$1 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep10" }, null, -1));
  3219. const _hoisted_10 = ["id"];
  3220. const _hoisted_11 = ["onclick"];
  3221. const _hoisted_12 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-up" }, null, -1));
  3222. const _hoisted_13 = ["onclick"];
  3223. const _hoisted_14 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-down" }, null, -1));
  3224. const _hoisted_15 = [
  3225. _hoisted_14
  3226. ];
  3227. const _hoisted_16 = { class: "gray" };
  3228. const _hoisted_17 = ["href"];
  3229. const _hoisted_18 = ["title"];
  3230. const _hoisted_19 = ["href"];
  3231. const _hoisted_20 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-info-circle" }, null, -1));
  3232. const _hoisted_21 = [
  3233. _hoisted_20
  3234. ];
  3235. const _hoisted_22 = ["href"];
  3236. const _hoisted_23 = { class: "my-tag" };
  3237. const _hoisted_24 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  3238. const _hoisted_25 = ["onClick"];
  3239. const _hoisted_26 = {
  3240. key: 0,
  3241. class: "my-box"
  3242. };
  3243. const _hoisted_27 = { class: "my-cell flex" };
  3244. const _hoisted_28 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "" }, "高赞回复", -1));
  3245. const _hoisted_29 = { class: "top-reply" };
  3246. const _hoisted_30 = { ref: "topReply" };
  3247. const _hoisted_31 = {
  3248. key: 1,
  3249. class: "my-box my-cell"
  3250. };
  3251. const _hoisted_32 = ["innerHTML"];
  3252. const _hoisted_33 = { class: "my-box comment-wrapper" };
  3253. const _hoisted_34 = {
  3254. key: 0,
  3255. class: "my-cell flex"
  3256. };
  3257. const _hoisted_35 = { class: "radio-group2" };
  3258. const _hoisted_36 = {
  3259. key: 0,
  3260. class: "read-notice"
  3261. };
  3262. const _hoisted_37 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上次打开:", -1));
  3263. const _hoisted_38 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  3264. const _hoisted_39 = [
  3265. _hoisted_38
  3266. ];
  3267. const _hoisted_40 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  3268. const _hoisted_41 = [
  3269. _hoisted_40
  3270. ];
  3271. const _hoisted_42 = { class: "my-cell flex" };
  3272. const _hoisted_43 = { key: 0 };
  3273. const _hoisted_44 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("strong", { class: "snow" }, "•", -1));
  3274. const _hoisted_45 = ["innerHTML"];
  3275. const _hoisted_46 = {
  3276. key: 0,
  3277. class: "loading-wrapper"
  3278. };
  3279. const _hoisted_47 = {
  3280. key: 1,
  3281. class: "comments"
  3282. };
  3283. const _hoisted_48 = {
  3284. key: 2,
  3285. id: "no-comments-yet"
  3286. };
  3287. const _hoisted_49 = { class: "my-cell flex" };
  3288. const _hoisted_50 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "添加一条新回复", -1));
  3289. const _hoisted_51 = { class: "notice-right gray" };
  3290. const _hoisted_52 = { class: "p1" };
  3291. const _hoisted_53 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "上下文", -1));
  3292. const _hoisted_54 = { class: "top-reply" };
  3293. const _hoisted_55 = ["onClick"];
  3294. const _hoisted_56 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", {
  3295. class: "fa fa-times",
  3296. "aria-hidden": "true"
  3297. }, null, -1));
  3298. const _hoisted_57 = [
  3299. _hoisted_56
  3300. ];
  3301. const _hoisted_58 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", {
  3302. class: "fa fa-long-arrow-up",
  3303. "aria-hidden": "true"
  3304. }, null, -1));
  3305. const _hoisted_59 = [
  3306. _hoisted_58
  3307. ];
  3308. const _hoisted_60 = {
  3309. key: 1,
  3310. class: "fa fa-refresh",
  3311. "aria-hidden": "true"
  3312. };
  3313. const _hoisted_61 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  3314. function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
  3315. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  3316. const _component_Point = vue.resolveComponent("Point");
  3317. const _component_Toolbar = vue.resolveComponent("Toolbar");
  3318. const _component_Tooltip = vue.resolveComponent("Tooltip");
  3319. const _component_Comment = vue.resolveComponent("Comment");
  3320. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  3321. const _component_PostEditor = vue.resolveComponent("PostEditor");
  3322. const _component_SingleComment = vue.resolveComponent("SingleComment");
  3323. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  3324. class: vue.normalizeClass(["post-detail", [$options.isNight ? "isNight" : "", $options.pageType, $options.isMobile ? "mobile" : ""]]),
  3325. ref: "detail",
  3326. onKeydown: _cache[26] || (_cache[26] = vue.withKeys(($event) => $options.close(), ["esc"])),
  3327. onScroll: _cache[27] || (_cache[27] = (...args) => $data.debounceScroll && $data.debounceScroll(...args)),
  3328. onClick: _cache[28] || (_cache[28] = ($event) => $options.close("space"))
  3329. }, [
  3330. vue.createElementVNode("div", {
  3331. ref: "main",
  3332. class: "main",
  3333. tabindex: "1",
  3334. onClick: _cache[25] || (_cache[25] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  3335. }, [
  3336. vue.createElementVNode("div", {
  3337. class: "main-wrapper",
  3338. ref: "mainWrapper",
  3339. style: vue.normalizeStyle({ width: $options.config.postWidth })
  3340. }, [
  3341. vue.createElementVNode("div", _hoisted_1$6, [
  3342. vue.createElementVNode("div", _hoisted_2$5, [
  3343. vue.createElementVNode("div", _hoisted_3$4, [
  3344. $options.post.member.avatar_large ? (vue.openBlock(), vue.createElementBlock("a", {
  3345. key: 0,
  3346. href: `/member/${$options.post.member.username}`
  3347. }, [
  3348. vue.createElementVNode("img", {
  3349. src: $options.post.member.avatar_large,
  3350. class: "avatar",
  3351. style: { "width": "73px", "height": "73px" },
  3352. border: "0",
  3353. align: "default",
  3354. alt: $options.post.member.username
  3355. }, null, 8, _hoisted_5$2)
  3356. ], 8, _hoisted_4$3)) : vue.createCommentVNode("", true)
  3357. ]),
  3358. _hoisted_6$2,
  3359. _hoisted_7$1,
  3360. vue.createElementVNode("a", {
  3361. href: $options.post.node.url
  3362. }, vue.toDisplayString($options.post.node.title), 9, _hoisted_8$1),
  3363. _hoisted_9$1,
  3364. vue.createElementVNode("h1", null, vue.toDisplayString($options.post.title), 1),
  3365. !$options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", {
  3366. key: 0,
  3367. id: `topic_${$options.post.id}_votes`,
  3368. class: "votes"
  3369. }, [
  3370. vue.createElementVNode("a", {
  3371. href: "javascript:",
  3372. onclick: `upVoteTopic(${$options.post.id});`,
  3373. class: "vote"
  3374. }, [
  3375. _hoisted_12,
  3376. vue.createTextVNode("   ")
  3377. ], 8, _hoisted_11),
  3378. vue.createTextVNode("   "),
  3379. vue.createElementVNode("a", {
  3380. href: "javascript:",
  3381. onclick: `downVoteTopic(${$options.post.id});`,
  3382. class: "vote"
  3383. }, _hoisted_15, 8, _hoisted_13)
  3384. ], 8, _hoisted_10)) : vue.createCommentVNode("", true),
  3385. vue.createTextVNode("   "),
  3386. vue.createElementVNode("small", _hoisted_16, [
  3387. vue.createElementVNode("a", {
  3388. href: `/member/${$options.post.member.username}`
  3389. }, vue.toDisplayString($options.post.member.username), 9, _hoisted_17),
  3390. vue.createTextVNode(" · "),
  3391. $options.post.member.createDate ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  3392. vue.createElementVNode("span", {
  3393. class: vue.normalizeClass($options.post.member.isNew && "danger")
  3394. }, vue.toDisplayString($options.post.member.createDate), 3),
  3395. vue.createTextVNode(" · ")
  3396. ], 64)) : vue.createCommentVNode("", true),
  3397. $options.post.createDateAgo ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  3398. vue.createElementVNode("span", {
  3399. title: $options.post.createDate
  3400. }, vue.toDisplayString($options.post.createDateAgo), 9, _hoisted_18),
  3401. vue.createTextVNode(" · ")
  3402. ], 64)) : vue.createCommentVNode("", true),
  3403. vue.createTextVNode(" " + vue.toDisplayString($options.post.clickCount) + " 次点击 ", 1),
  3404. $options.isMy ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
  3405. vue.createTextVNode("   "),
  3406. vue.createElementVNode("a", {
  3407. href: `/t/${$options.post.id}/info`
  3408. }, _hoisted_21, 8, _hoisted_19),
  3409. vue.createTextVNode("   "),
  3410. vue.createElementVNode("a", {
  3411. href: `/append/topic/${$options.post.id}`,
  3412. class: "op"
  3413. }, "APPEND", 8, _hoisted_22)
  3414. ], 64)) : vue.createCommentVNode("", true)
  3415. ]),
  3416. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  3417. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  3418. return vue.openBlock(), vue.createElementBlock("span", _hoisted_23, [
  3419. _hoisted_24,
  3420. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  3421. vue.createElementVNode("i", {
  3422. class: "fa fa-trash-o remove",
  3423. onClick: ($event) => $options.removeTag(i)
  3424. }, null, 8, _hoisted_25)
  3425. ]);
  3426. }), 256)),
  3427. vue.createElementVNode("span", {
  3428. class: "add-tag ago",
  3429. onClick: _cache[0] || (_cache[0] = (...args) => $options.addTag && $options.addTag(...args)),
  3430. title: "添加标签"
  3431. }, "+")
  3432. ], 64)) : vue.createCommentVNode("", true)
  3433. ]),
  3434. vue.createVNode(_component_BaseHtmlRender, {
  3435. html: $options.post.headerTemplate
  3436. }, null, 8, ["html"]),
  3437. vue.createVNode(_component_Toolbar, {
  3438. onReply: _cache[1] || (_cache[1] = ($event) => $data.isSticky = !$data.isSticky)
  3439. }, {
  3440. default: vue.withCtx(() => [
  3441. vue.createVNode(_component_Point, {
  3442. onAddThank: $options.addThank,
  3443. onRecallThank: $options.recallThank,
  3444. full: false,
  3445. item: {
  3446. isThanked: $options.post.isThanked,
  3447. thankCount: $options.post.thankCount,
  3448. username: $options.post.username
  3449. },
  3450. "api-url": "topic/" + $options.post.id
  3451. }, null, 8, ["onAddThank", "onRecallThank", "item", "api-url"])
  3452. ]),
  3453. _: 1
  3454. })
  3455. ]),
  3456. $options.topReply.length && $options.config.showTopReply ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_26, [
  3457. vue.createElementVNode("div", _hoisted_27, [
  3458. _hoisted_28,
  3459. vue.createElementVNode("div", _hoisted_29, [
  3460. vue.createVNode(_component_Tooltip, { title: "收起高赞回复" }, {
  3461. default: vue.withCtx(() => [
  3462. vue.createElementVNode("i", {
  3463. class: "fa fa-compress",
  3464. onClick: _cache[2] || (_cache[2] = (...args) => $options.collapseTopReplyList && $options.collapseTopReplyList(...args))
  3465. })
  3466. ]),
  3467. _: 1
  3468. })
  3469. ])
  3470. ]),
  3471. vue.createElementVNode("div", _hoisted_30, [
  3472. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.topReply, (item, index) => {
  3473. return vue.openBlock(), vue.createBlock(_component_Comment, {
  3474. key: item.floor,
  3475. type: "top",
  3476. modelValue: $options.topReply[index],
  3477. "onUpdate:modelValue": ($event) => $options.topReply[index] = $event
  3478. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  3479. }), 128))
  3480. ], 512)
  3481. ])) : vue.createCommentVNode("", true),
  3482. $options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_31, [
  3483. vue.createElementVNode("div", {
  3484. class: "inner",
  3485. innerHTML: $options.post.fr
  3486. }, null, 8, _hoisted_32)
  3487. ])) : vue.createCommentVNode("", true),
  3488. vue.createElementVNode("div", _hoisted_33, [
  3489. $options.post.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  3490. $options.config.showToolbar ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_34, [
  3491. vue.createElementVNode("div", _hoisted_35, [
  3492. vue.createVNode(_component_Tooltip, { title: "不隐藏@用户" }, {
  3493. default: vue.withCtx(() => [
  3494. vue.createElementVNode("div", {
  3495. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.FloorInFloor ? "active" : ""]),
  3496. onClick: _cache[3] || (_cache[3] = ($event) => $options.changeOption($options.CommentDisplayType.FloorInFloor))
  3497. }, "楼中楼(@) ", 2)
  3498. ]),
  3499. _: 1
  3500. }),
  3501. vue.createVNode(_component_Tooltip, { title: "隐藏第一个@用户,双击内容可显示原文" }, {
  3502. default: vue.withCtx(() => [
  3503. vue.createElementVNode("div", {
  3504. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.FloorInFloorNoCallUser ? "active" : ""]),
  3505. onClick: _cache[4] || (_cache[4] = ($event) => $options.changeOption($options.CommentDisplayType.FloorInFloorNoCallUser))
  3506. }, "楼中楼 ", 2)
  3507. ]),
  3508. _: 1
  3509. }),
  3510. vue.createVNode(_component_Tooltip, { title: "重复显示楼中楼的回复" }, {
  3511. default: vue.withCtx(() => [
  3512. vue.createElementVNode("div", {
  3513. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.FloorInFloorNested ? "active" : ""]),
  3514. onClick: _cache[5] || (_cache[5] = ($event) => $options.changeOption($options.CommentDisplayType.FloorInFloorNested))
  3515. }, "冗余楼中楼 ", 2)
  3516. ]),
  3517. _: 1
  3518. }),
  3519. vue.createElementVNode("div", {
  3520. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.Like ? "active" : ""]),
  3521. onClick: _cache[6] || (_cache[6] = ($event) => $options.changeOption($options.CommentDisplayType.Like))
  3522. }, "感谢 ", 2),
  3523. vue.createElementVNode("div", {
  3524. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.OnlyOp ? "active" : ""]),
  3525. onClick: _cache[7] || (_cache[7] = ($event) => $options.changeOption($options.CommentDisplayType.OnlyOp))
  3526. }, "只看楼主 ", 2),
  3527. vue.createElementVNode("div", {
  3528. class: vue.normalizeClass(["radio", $props.displayType === $options.CommentDisplayType.V2exOrigin ? "active" : ""]),
  3529. onClick: _cache[8] || (_cache[8] = ($event) => $options.changeOption($options.CommentDisplayType.V2exOrigin))
  3530. }, "V2原版 ", 2)
  3531. ]),
  3532. $data.read.floor || $data.read.total ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_36, [
  3533. _hoisted_37,
  3534. $data.read.floor ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  3535. vue.createElementVNode("span", null, [
  3536. vue.createTextVNode("阅读到"),
  3537. vue.createElementVNode("b", null, vue.toDisplayString($data.read.floor), 1),
  3538. vue.createTextVNode("楼")
  3539. ]),
  3540. vue.createElementVNode("div", {
  3541. class: "jump jump1",
  3542. onClick: _cache[9] || (_cache[9] = ($event) => $options.jump($data.read.floor))
  3543. }, _hoisted_39)
  3544. ], 64)) : vue.createCommentVNode("", true),
  3545. vue.createElementVNode("span", null, [
  3546. vue.createTextVNode("总楼层"),
  3547. vue.createElementVNode("b", null, vue.toDisplayString($data.read.total), 1)
  3548. ]),
  3549. vue.createElementVNode("div", {
  3550. class: "jump",
  3551. onClick: _cache[10] || (_cache[10] = ($event) => $options.jump($data.read.total))
  3552. }, _hoisted_41)
  3553. ])) : vue.createCommentVNode("", true)
  3554. ])) : vue.createCommentVNode("", true),
  3555. vue.createElementVNode("div", _hoisted_42, [
  3556. vue.createElementVNode("span", null, [
  3557. vue.createTextVNode(vue.toDisplayString($options.post.replyCount) + " 条回复 ", 1),
  3558. $options.post.createDate ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_43, [
  3559. vue.createTextVNode("  "),
  3560. _hoisted_44,
  3561. vue.createTextVNode("  " + vue.toDisplayString($options.post.createDate), 1)
  3562. ])) : vue.createCommentVNode("", true)
  3563. ]),
  3564. !$options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", {
  3565. key: 0,
  3566. class: "fr",
  3567. innerHTML: $options.post.fr
  3568. }, null, 8, _hoisted_45)) : vue.createCommentVNode("", true)
  3569. ])
  3570. ], 64)) : vue.createCommentVNode("", true),
  3571. $options.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  3572. $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_46, [
  3573. vue.createVNode(_component_BaseLoading, { size: "large" })
  3574. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_47, [
  3575. $props.modelValue ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 0 }, vue.renderList($options.replyList, (item, index) => {
  3576. return vue.openBlock(), vue.createBlock(_component_Comment, {
  3577. key: item.floor,
  3578. modelValue: $options.replyList[index],
  3579. "onUpdate:modelValue": ($event) => $options.replyList[index] = $event
  3580. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  3581. }), 128)) : vue.createCommentVNode("", true)
  3582. ]))
  3583. ], 64)) : vue.createCommentVNode("", true)
  3584. ]),
  3585. !($options.replyList.length || $props.loading) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_48, "目前尚无回复")) : vue.createCommentVNode("", true),
  3586. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
  3587. key: 3,
  3588. class: vue.normalizeClass(["my-box", { "sticky": $data.isSticky }]),
  3589. ref: "replyBox"
  3590. }, [
  3591. vue.createElementVNode("div", _hoisted_49, [
  3592. _hoisted_50,
  3593. vue.createElementVNode("div", _hoisted_51, [
  3594. $data.isSticky ? (vue.openBlock(), vue.createElementBlock("a", {
  3595. key: 0,
  3596. style: { "margin-right": "2rem" },
  3597. onClick: _cache[11] || (_cache[11] = ($event) => $data.isSticky = false)
  3598. }, "取消回复框停靠")) : vue.createCommentVNode("", true),
  3599. vue.createElementVNode("a", {
  3600. onClick: _cache[12] || (_cache[12] = (...args) => $options.scrollTop && $options.scrollTop(...args))
  3601. }, "回到顶部")
  3602. ])
  3603. ]),
  3604. vue.createElementVNode("div", _hoisted_52, [
  3605. vue.createVNode(_component_PostEditor, {
  3606. onClose: $options.goBottom,
  3607. ref: "post-editor",
  3608. useType: "reply-post",
  3609. onClick: _cache[13] || (_cache[13] = ($event) => $data.isSticky = true)
  3610. }, null, 8, ["onClose"])
  3611. ])
  3612. ], 2)) : vue.createCommentVNode("", true)
  3613. ], 4),
  3614. $data.showRelationReply ? (vue.openBlock(), vue.createElementBlock("div", {
  3615. key: 0,
  3616. class: "relationReply",
  3617. onClick: _cache[17] || (_cache[17] = ($event) => $options.close("space"))
  3618. }, [
  3619. vue.createElementVNode("div", {
  3620. class: "my-cell flex",
  3621. onClick: _cache[15] || (_cache[15] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  3622. }, [
  3623. _hoisted_53,
  3624. vue.createElementVNode("div", _hoisted_54, [
  3625. vue.createElementVNode("i", {
  3626. class: "fa fa-times",
  3627. onClick: _cache[14] || (_cache[14] = ($event) => $data.showRelationReply = false)
  3628. })
  3629. ])
  3630. ]),
  3631. vue.createElementVNode("div", {
  3632. class: "comments",
  3633. onClick: _cache[16] || (_cache[16] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  3634. }, [
  3635. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.relationReply, (item, index) => {
  3636. return vue.openBlock(), vue.createBlock(_component_SingleComment, {
  3637. "is-right": item.username === $data.targetUser.right,
  3638. key: item.floor,
  3639. comment: item
  3640. }, null, 8, ["is-right", "comment"]);
  3641. }), 128))
  3642. ])
  3643. ])) : vue.createCommentVNode("", true),
  3644. $data.showCallList && $options.filterCallList.length ? (vue.openBlock(), vue.createElementBlock("div", {
  3645. key: 1,
  3646. class: "call-list",
  3647. style: vue.normalizeStyle($data.callStyle)
  3648. }, [
  3649. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.filterCallList, (item, index) => {
  3650. return vue.openBlock(), vue.createElementBlock("div", {
  3651. class: vue.normalizeClass(["call-item", { select: index === $data.selectCallIndex }]),
  3652. onClick: ($event) => $options.setCall(item)
  3653. }, [
  3654. vue.createElementVNode("a", null, vue.toDisplayString(item), 1)
  3655. ], 10, _hoisted_55);
  3656. }), 256))
  3657. ], 4)) : vue.createCommentVNode("", true),
  3658. vue.createElementVNode("div", {
  3659. class: "close-btn",
  3660. onClick: _cache[18] || (_cache[18] = ($event) => $options.close("btn"))
  3661. }, _hoisted_57),
  3662. vue.createElementVNode("div", {
  3663. class: "scroll-top gray",
  3664. onClick: _cache[19] || (_cache[19] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
  3665. }, _hoisted_59),
  3666. vue.createElementVNode("div", {
  3667. class: "refresh gray",
  3668. onClick: _cache[20] || (_cache[20] = vue.withModifiers(($event) => _ctx.$emit("refresh"), ["stop"]))
  3669. }, [
  3670. $props.refreshLoading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, { key: 0 })) : (vue.openBlock(), vue.createElementBlock("i", _hoisted_60))
  3671. ]),
  3672. vue.createElementVNode("div", {
  3673. class: "scroll-to gray",
  3674. onClick: _cache[24] || (_cache[24] = vue.withModifiers(($event) => $options.jump($data.currentFloor), ["stop"]))
  3675. }, [
  3676. _hoisted_61,
  3677. vue.withDirectives(vue.createElementVNode("input", {
  3678. type: "text",
  3679. "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => $data.currentFloor = $event),
  3680. onClick: _cache[22] || (_cache[22] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"])),
  3681. onKeydown: _cache[23] || (_cache[23] = vue.withKeys(($event) => $options.jump($data.currentFloor), ["enter"]))
  3682. }, null, 544), [
  3683. [vue.vModelText, $data.currentFloor]
  3684. ])
  3685. ])
  3686. ], 512)
  3687. ], 34)), [
  3688. [vue.vShow, $props.modelValue]
  3689. ]);
  3690. }
  3691. const PostDetail = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$2], ["__scopeId", "data-v-7f8ab1e3"]]);
  3692. const _withScopeId$4 = (n2) => (vue.pushScopeId("data-v-618144eb"), n2 = n2(), vue.popScopeId(), n2);
  3693. const _hoisted_1$5 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  3694. width: "24",
  3695. height: "24",
  3696. viewBox: "0 0 48 48",
  3697. fill: "none",
  3698. xmlns: "http://www.w3.org/2000/svg"
  3699. }, [
  3700. /* @__PURE__ */ vue.createElementVNode("path", {
  3701. d: "M17 32L19.1875 27M31 32L28.8125 27M19.1875 27L24 16L28.8125 27M19.1875 27H28.8125",
  3702. stroke: "#929596",
  3703. "stroke-width": "4",
  3704. "stroke-linecap": "round",
  3705. "stroke-linejoin": "round"
  3706. }),
  3707. /* @__PURE__ */ vue.createElementVNode("path", {
  3708. d: "M43.1999 20C41.3468 10.871 33.2758 4 23.5999 4C13.9241 4 5.85308 10.871 4 20L10 18",
  3709. stroke: "#929596",
  3710. "stroke-width": "4",
  3711. "stroke-linecap": "round",
  3712. "stroke-linejoin": "round"
  3713. }),
  3714. /* @__PURE__ */ vue.createElementVNode("path", {
  3715. d: "M4 28C5.85308 37.129 13.9241 44 23.5999 44C33.2758 44 41.3468 37.129 43.1999 28L38 30",
  3716. stroke: "#929596",
  3717. "stroke-width": "4",
  3718. "stroke-linecap": "round",
  3719. "stroke-linejoin": "round"
  3720. })
  3721. ], -1));
  3722. const _hoisted_2$4 = { key: 1 };
  3723. const _sfc_main$5 = {
  3724. __name: "Base64Tooltip",
  3725. setup(__props) {
  3726. const tooltip = vue.ref(null);
  3727. const show = vue.ref(false);
  3728. const originalText = vue.ref("");
  3729. const decodeText = vue.ref("");
  3730. const styleObject = vue.reactive({
  3731. left: "-100vw",
  3732. top: "-100vh"
  3733. });
  3734. vue.onMounted(() => {
  3735. eventBus.on(CMD.SHOW_TOOLTIP, ({ text, e: e2 }) => {
  3736. setTimeout(() => show.value = true);
  3737. originalText.value = text;
  3738. decodeText.value = "";
  3739. styleObject.left = e2.clientX + "px";
  3740. styleObject.top = e2.clientY + 20 + "px";
  3741. });
  3742. window.addEventListener("click", (e2) => {
  3743. if (!tooltip.value)
  3744. return;
  3745. if (!tooltip.value.contains(e2.target) && show.value) {
  3746. show.value = false;
  3747. }
  3748. }, { capture: true });
  3749. const fn = () => show.value && (show.value = false);
  3750. $(".post-detail", window.win().doc).on("scroll", fn);
  3751. });
  3752. function copy() {
  3753. if (window.win().navigator.clipboard) {
  3754. window.win().navigator.clipboard.writeText(decodeText.value);
  3755. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "复制成功" });
  3756. } else {
  3757. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "复制失败!浏览器不支持!" });
  3758. }
  3759. }
  3760. function base64ToArrayBuffer(base64) {
  3761. let binary_string = window.atob(base64);
  3762. let len = binary_string.length;
  3763. let bytes = new Uint8Array(len);
  3764. for (let i = 0; i < len; i++) {
  3765. bytes[i] = binary_string.charCodeAt(i);
  3766. }
  3767. return bytes.buffer;
  3768. }
  3769. function decode() {
  3770. try {
  3771. new Blob([base64ToArrayBuffer(originalText.value)]).text().then((r2) => {
  3772. decodeText.value = r2;
  3773. });
  3774. } catch (e2) {
  3775. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "Base64解码失败!不是标准数据!" });
  3776. }
  3777. }
  3778. return (_ctx, _cache) => {
  3779. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  3780. class: "base64_tooltip",
  3781. style: vue.normalizeStyle(styleObject),
  3782. onClick: decode,
  3783. ref_key: "tooltip",
  3784. ref: tooltip
  3785. }, [
  3786. !decodeText.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  3787. vue.createTextVNode(" Base64解码:" + vue.toDisplayString(originalText.value) + " ", 1),
  3788. _hoisted_1$5
  3789. ], 64)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$4, [
  3790. vue.createElementVNode("span", null, vue.toDisplayString(decodeText.value), 1),
  3791. vue.createVNode(BaseButton, {
  3792. class: "btn",
  3793. size: "small",
  3794. onClick: copy
  3795. }, {
  3796. default: vue.withCtx(() => [
  3797. vue.createTextVNode("点击复制")
  3798. ]),
  3799. _: 1
  3800. })
  3801. ]))
  3802. ], 4)), [
  3803. [vue.vShow, show.value]
  3804. ]);
  3805. };
  3806. }
  3807. };
  3808. const Base64Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-618144eb"]]);
  3809. const _sfc_main$4 = {
  3810. name: "Msg",
  3811. props: {
  3812. type: "",
  3813. text: ""
  3814. },
  3815. created() {
  3816. setTimeout(() => {
  3817. this.$emit("close");
  3818. }, 3e3);
  3819. }
  3820. };
  3821. const _withScopeId$3 = (n2) => (vue.pushScopeId("data-v-defce7f2"), n2 = n2(), vue.popScopeId(), n2);
  3822. const _hoisted_1$4 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  3823. width: "24",
  3824. height: "24",
  3825. viewBox: "0 0 48 48",
  3826. fill: "none",
  3827. xmlns: "http://www.w3.org/2000/svg"
  3828. }, [
  3829. /* @__PURE__ */ vue.createElementVNode("path", {
  3830. d: "M14 14L34 34",
  3831. stroke: "#ffffff",
  3832. "stroke-width": "4",
  3833. "stroke-linecap": "round",
  3834. "stroke-linejoin": "round"
  3835. }),
  3836. /* @__PURE__ */ vue.createElementVNode("path", {
  3837. d: "M14 34L34 14",
  3838. stroke: "#ffffff",
  3839. "stroke-width": "4",
  3840. "stroke-linecap": "round",
  3841. "stroke-linejoin": "round"
  3842. })
  3843. ], -1));
  3844. const _hoisted_2$3 = [
  3845. _hoisted_1$4
  3846. ];
  3847. const _hoisted_3$3 = { class: "right" };
  3848. function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
  3849. return vue.openBlock(), vue.createElementBlock("div", {
  3850. class: vue.normalizeClass(["msg", $props.type])
  3851. }, [
  3852. vue.createElementVNode("div", {
  3853. class: "left",
  3854. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
  3855. }, _hoisted_2$3),
  3856. vue.createElementVNode("div", _hoisted_3$3, vue.toDisplayString($props.text), 1)
  3857. ], 2);
  3858. }
  3859. const Msg = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$1], ["__scopeId", "data-v-defce7f2"]]);
  3860. const _withScopeId$2 = (n2) => (vue.pushScopeId("data-v-674b86aa"), n2 = n2(), vue.popScopeId(), n2);
  3861. const _hoisted_1$3 = {
  3862. key: 0,
  3863. class: "tag-modal modal"
  3864. };
  3865. const _hoisted_2$2 = { class: "wrapper" };
  3866. const _hoisted_3$2 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 添加标签 ", -1));
  3867. const _hoisted_4$2 = { class: "option" };
  3868. const _hoisted_5$1 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户:", -1));
  3869. const _hoisted_6$1 = { class: "btns" };
  3870. const _sfc_main$3 = {
  3871. __name: "TagModal",
  3872. props: ["tags"],
  3873. emits: ["update:tags"],
  3874. setup(__props, { emit: __emit }) {
  3875. const tagModal = vue.reactive({
  3876. show: false,
  3877. currentUsername: "",
  3878. tag: ""
  3879. });
  3880. const props = __props;
  3881. const emit = __emit;
  3882. const inputRef = vue.ref();
  3883. vue.onMounted(() => {
  3884. eventBus.on(CMD.ADD_TAG, (username) => {
  3885. tagModal.currentUsername = username;
  3886. tagModal.show = true;
  3887. vue.nextTick(() => {
  3888. inputRef.value.focus();
  3889. });
  3890. });
  3891. });
  3892. async function addTag() {
  3893. if (!tagModal.tag) {
  3894. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请输入标签" });
  3895. return;
  3896. }
  3897. let oldTag = window.clone(props.tags);
  3898. let tempTag = window.clone(props.tags);
  3899. let userTags = tempTag[tagModal.currentUsername] ?? [];
  3900. let rIndex = userTags.findIndex((v) => v === tagModal.tag);
  3901. if (rIndex > -1) {
  3902. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "标签已存在!" });
  3903. return;
  3904. } else {
  3905. userTags.push(tagModal.tag);
  3906. }
  3907. tempTag[tagModal.currentUsername] = userTags;
  3908. emit("update:tags", tempTag);
  3909. tagModal.tag = "";
  3910. tagModal.show = false;
  3911. let res = await window.parse.saveTags(tempTag);
  3912. if (!res) {
  3913. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签添加失败!" });
  3914. emit("update:tags", oldTag);
  3915. }
  3916. }
  3917. return (_ctx, _cache) => {
  3918. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  3919. default: vue.withCtx(() => [
  3920. tagModal.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
  3921. vue.createElementVNode("div", {
  3922. class: "mask",
  3923. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => tagModal.show = false, ["stop"]))
  3924. }),
  3925. vue.createElementVNode("div", _hoisted_2$2, [
  3926. _hoisted_3$2,
  3927. vue.createElementVNode("div", _hoisted_4$2, [
  3928. _hoisted_5$1,
  3929. vue.createElementVNode("div", null, [
  3930. vue.createElementVNode("b", null, vue.toDisplayString(tagModal.currentUsername), 1)
  3931. ])
  3932. ]),
  3933. vue.withDirectives(vue.createElementVNode("input", {
  3934. type: "text",
  3935. ref_key: "inputRef",
  3936. ref: inputRef,
  3937. style: { "width": "100%" },
  3938. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tagModal.tag = $event),
  3939. onKeydown: vue.withKeys(addTag, ["enter"])
  3940. }, null, 544), [
  3941. [vue.vModelText, tagModal.tag]
  3942. ]),
  3943. vue.createElementVNode("div", _hoisted_6$1, [
  3944. vue.createVNode(BaseButton, {
  3945. type: "link",
  3946. onClick: _cache[2] || (_cache[2] = ($event) => tagModal.show = false)
  3947. }, {
  3948. default: vue.withCtx(() => [
  3949. vue.createTextVNode("取消")
  3950. ]),
  3951. _: 1
  3952. }),
  3953. vue.createVNode(BaseButton, { onClick: addTag }, {
  3954. default: vue.withCtx(() => [
  3955. vue.createTextVNode("确定")
  3956. ]),
  3957. _: 1
  3958. })
  3959. ])
  3960. ])
  3961. ])) : vue.createCommentVNode("", true)
  3962. ]),
  3963. _: 1
  3964. });
  3965. };
  3966. }
  3967. };
  3968. const TagModal = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-674b86aa"]]);
  3969. const _hoisted_1$2 = { class: "msgs" };
  3970. const _sfc_main$2 = {
  3971. __name: "MsgModal",
  3972. setup(__props) {
  3973. const msgList = vue.reactive([
  3974. // {type: 'success', text: '123', id: Date.now()}
  3975. ]);
  3976. vue.onMounted(() => {
  3977. eventBus.on(CMD.SHOW_MSG, (val) => {
  3978. msgList.push({ ...val, id: Date.now() });
  3979. });
  3980. });
  3981. function removeMsg(id) {
  3982. let rIndex = msgList.findIndex((item) => item.id === id);
  3983. if (rIndex > -1) {
  3984. msgList.splice(rIndex, 1);
  3985. }
  3986. }
  3987. return (_ctx, _cache) => {
  3988. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
  3989. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(msgList, (v) => {
  3990. return vue.openBlock(), vue.createBlock(Msg, {
  3991. key: v.id,
  3992. type: v.type,
  3993. text: v.text,
  3994. onClose: ($event) => removeMsg(v.id)
  3995. }, null, 8, ["type", "text", "onClose"]);
  3996. }), 128))
  3997. ]);
  3998. };
  3999. }
  4000. };
  4001. const MsgModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b73f4332"]]);
  4002. let u = ".__cf_email__", f = "data-cfemail", d = document.createElement("div");
  4003. function e(e2) {
  4004. console.error(e2);
  4005. }
  4006. function r(e2, t) {
  4007. let r2 = e2.substr(t, 2);
  4008. return parseInt(r2, 16);
  4009. }
  4010. function n(href, index) {
  4011. let o = "", a = r(href, index);
  4012. for (let i = index + 2; i < href.length; i += 2) {
  4013. let l = r(href, i) ^ a;
  4014. o += String.fromCharCode(l);
  4015. }
  4016. try {
  4017. o = decodeURIComponent(escape(o));
  4018. } catch (u2) {
  4019. e(u2);
  4020. }
  4021. d.innerHTML = '<a href="' + o.replace(/"/g, "&quot;") + '"></a>';
  4022. return d.childNodes[0].getAttribute("href") || "";
  4023. }
  4024. function decodeEmail(body) {
  4025. try {
  4026. let as = body.find(u);
  4027. as.each(function() {
  4028. try {
  4029. let o = this, a = o.parentNode, i = o.getAttribute(f);
  4030. if (i) {
  4031. let l = n(i, 0), d2 = document.createTextNode(l);
  4032. a.replaceChild(d2, o);
  4033. }
  4034. } catch (h) {
  4035. e(h);
  4036. }
  4037. });
  4038. } catch (s) {
  4039. e(s);
  4040. }
  4041. }
  4042. const _withScopeId$1 = (n2) => (vue.pushScopeId("data-v-882b932b"), n2 = n2(), vue.popScopeId(), n2);
  4043. const _hoisted_1$1 = {
  4044. key: 0,
  4045. class: "tag-modal modal"
  4046. };
  4047. const _hoisted_2$1 = { class: "modal-root" };
  4048. const _hoisted_3$1 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 提醒系统 ", -1));
  4049. const _hoisted_4$1 = ["innerHTML"];
  4050. const _sfc_main$1 = {
  4051. __name: "NotificationModal",
  4052. props: ["modelValue", "h"],
  4053. emits: ["update:modelValue"],
  4054. setup(__props, { emit: __emit }) {
  4055. const emit = __emit;
  4056. vue.onMounted(() => {
  4057. });
  4058. function close() {
  4059. emit("update:modelValue", false);
  4060. }
  4061. return (_ctx, _cache) => {
  4062. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  4063. default: vue.withCtx(() => [
  4064. __props.modelValue ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
  4065. vue.createElementVNode("div", {
  4066. class: "mask",
  4067. onClick: vue.withModifiers(close, ["stop"])
  4068. }),
  4069. vue.createElementVNode("div", _hoisted_2$1, [
  4070. vue.createElementVNode("div", { class: "modal-header" }, [
  4071. _hoisted_3$1,
  4072. vue.createElementVNode("i", {
  4073. class: "fa fa-times",
  4074. onClick: close
  4075. })
  4076. ]),
  4077. vue.createElementVNode("div", {
  4078. innerHTML: __props.h,
  4079. class: "modal-body"
  4080. }, null, 8, _hoisted_4$1)
  4081. ])
  4082. ])) : vue.createCommentVNode("", true)
  4083. ]),
  4084. _: 1
  4085. });
  4086. };
  4087. }
  4088. };
  4089. const NotificationModal = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-882b932b"]]);
  4090. var _GM_notification = /* @__PURE__ */ (() => typeof GM_notification != "undefined" ? GM_notification : void 0)();
  4091. var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)();
  4092. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  4093. const DefaultPost = {
  4094. allReplyUsers: [],
  4095. content_rendered: "",
  4096. createDate: "",
  4097. createDateAgo: "",
  4098. fr: "",
  4099. replyList: [],
  4100. nestedReplies: [],
  4101. nestedRedundReplies: [],
  4102. username: "",
  4103. url: "",
  4104. member: {},
  4105. node: {
  4106. title: "",
  4107. url: ""
  4108. },
  4109. headerTemplate: "",
  4110. title: "",
  4111. id: "",
  4112. type: "post",
  4113. once: "",
  4114. replyCount: 0,
  4115. clickCount: 0,
  4116. thankCount: 0,
  4117. collectCount: 0,
  4118. lastReadFloor: 0,
  4119. isFavorite: false,
  4120. isIgnore: false,
  4121. isThanked: false,
  4122. isReport: false,
  4123. inList: false
  4124. };
  4125. const DefaultUser = {
  4126. tagPrefix: "--用户标签--",
  4127. tags: {},
  4128. tagsId: "",
  4129. username: "",
  4130. avatar: "",
  4131. readPrefix: "--已读楼层--",
  4132. readNoteItemId: "",
  4133. readList: {},
  4134. imgurPrefix: "--imgur图片删除hash--",
  4135. imgurList: {},
  4136. imgurNoteId: ""
  4137. };
  4138. const DefaultConfig = {
  4139. showToolbar: true,
  4140. showPreviewBtn: true,
  4141. autoOpenDetail: true,
  4142. openTag: false,
  4143. //给用户打标签
  4144. clickPostItemOpenDetail: true,
  4145. closePostDetailBySpace: true,
  4146. //点击空白处关闭详情
  4147. contentAutoCollapse: true,
  4148. //正文超长自动折叠
  4149. viewType: "table",
  4150. commentDisplayType: CommentDisplayType.FloorInFloorNoCallUser,
  4151. newTabOpen: false,
  4152. //新标签打开
  4153. base64: true,
  4154. //base功能
  4155. sov2ex: false,
  4156. postWidth: "",
  4157. showTopReply: true,
  4158. topReplyLoveMinCount: 3,
  4159. topReplyCount: 3,
  4160. autoJumpLastReadFloor: false,
  4161. rememberLastReadFloor: false,
  4162. autoSignin: true,
  4163. customBgColor: "",
  4164. version: 1,
  4165. collectBrowserNotice: false,
  4166. fontSizeType: "normal"
  4167. };
  4168. const DefaultVal = {
  4169. pageType: void 0,
  4170. pageData: { pageNo: 1 },
  4171. targetUserName: "",
  4172. currentVersion: 1,
  4173. isNight: false,
  4174. cb: null,
  4175. stopMe: null,
  4176. postList: [],
  4177. git: "https://github.com/zyronon/web-scripts",
  4178. shortGit: "zyronon/web-scripts",
  4179. issue: "https://github.com/zyronon/web-scripts/issues"
  4180. };
  4181. const functions = {
  4182. //获取所有回复
  4183. getAllReply(repliesMap = []) {
  4184. return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
  4185. pre = pre.concat(i.replyList);
  4186. return pre;
  4187. }, []);
  4188. },
  4189. //查找子回复
  4190. findChildren(item, endList, all) {
  4191. var _a;
  4192. const fn = (child, endList2, parent) => {
  4193. child.level = parent.level + 1;
  4194. let rIndex = all.findIndex((v) => v.floor === child.floor);
  4195. if (rIndex > -1) {
  4196. all[rIndex].isUse = true;
  4197. }
  4198. parent.children.push(this.findChildren(child, endList2, all));
  4199. };
  4200. item.children = [];
  4201. let floorReplyList = [];
  4202. for (let i = 0; i < endList.length; i++) {
  4203. let currentItem = endList[i];
  4204. if (currentItem.isUse)
  4205. continue;
  4206. if (currentItem.replyFloor === item.floor) {
  4207. if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
  4208. currentItem.isUse = true;
  4209. floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
  4210. } else {
  4211. currentItem.isWrong = true;
  4212. }
  4213. }
  4214. }
  4215. floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
  4216. fn(currentItem, endList2, item);
  4217. });
  4218. let nextMeIndex = endList.findIndex((v) => {
  4219. var _a2;
  4220. return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
  4221. });
  4222. let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
  4223. for (let i = 0; i < findList.length; i++) {
  4224. let currentItem = findList[i];
  4225. if (currentItem.isUse)
  4226. continue;
  4227. if (currentItem.replyUsers.length === 1) {
  4228. if (currentItem.replyFloor !== -1) {
  4229. if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
  4230. continue;
  4231. }
  4232. }
  4233. let endList2 = endList.slice(i + 1);
  4234. if (currentItem.username === item.username) {
  4235. if (currentItem.replyUsers[0] === item.username) {
  4236. fn(currentItem, endList2, item);
  4237. }
  4238. break;
  4239. } else {
  4240. if (currentItem.replyUsers[0] === item.username) {
  4241. fn(currentItem, endList2, item);
  4242. }
  4243. }
  4244. } else {
  4245. if (currentItem.username === item.username)
  4246. break;
  4247. }
  4248. }
  4249. item.children = item.children.sort((a, b) => a.floor - b.floor);
  4250. return item;
  4251. },
  4252. //生成嵌套回复
  4253. createNestedList(allList = []) {
  4254. if (!allList.length)
  4255. return [];
  4256. let list = window.clone(allList);
  4257. let nestedList = [];
  4258. list.map((item, index) => {
  4259. let startList = list.slice(0, index);
  4260. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  4261. let endList = list.slice(index + 1);
  4262. if (index === 0) {
  4263. nestedList.push(this.findChildren(item, endList, list));
  4264. } else {
  4265. if (!item.isUse) {
  4266. let isOneLevelReply = false;
  4267. if (item.replyUsers.length) {
  4268. if (item.replyUsers.length > 1) {
  4269. isOneLevelReply = true;
  4270. } else {
  4271. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  4272. }
  4273. } else {
  4274. isOneLevelReply = true;
  4275. }
  4276. if (isOneLevelReply) {
  4277. item.level = 0;
  4278. nestedList.push(this.findChildren(item, endList, list));
  4279. }
  4280. }
  4281. }
  4282. });
  4283. return nestedList;
  4284. },
  4285. //生成嵌套冗余回复
  4286. createNestedRedundantList(allList = []) {
  4287. if (!allList.length)
  4288. return [];
  4289. let list = window.clone(allList);
  4290. let nestedList = [];
  4291. list.map((item, index) => {
  4292. let startList = list.slice(0, index);
  4293. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  4294. let endList = list.slice(index + 1);
  4295. if (index === 0) {
  4296. nestedList.push(this.findChildren(item, endList, list));
  4297. } else {
  4298. if (!item.isUse) {
  4299. let isOneLevelReply = false;
  4300. if (item.replyUsers.length) {
  4301. if (item.replyUsers.length > 1) {
  4302. isOneLevelReply = true;
  4303. } else {
  4304. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  4305. }
  4306. } else {
  4307. isOneLevelReply = true;
  4308. }
  4309. if (isOneLevelReply) {
  4310. item.level = 0;
  4311. nestedList.push(this.findChildren(item, endList, list));
  4312. }
  4313. } else {
  4314. let newItem = window.clone(item);
  4315. newItem.children = [];
  4316. newItem.level = 0;
  4317. newItem.isDup = true;
  4318. nestedList.push(newItem);
  4319. }
  4320. }
  4321. });
  4322. return nestedList;
  4323. },
  4324. //解析A标签
  4325. parseA(a) {
  4326. let href = a.href;
  4327. let id;
  4328. if (href.includes("/t/")) {
  4329. id = a.pathname.substring("/t/".length);
  4330. }
  4331. return { href, id, title: a.innerText };
  4332. },
  4333. //图片链接转Img标签
  4334. checkPhotoLink2Img(str) {
  4335. if (!str)
  4336. return;
  4337. try {
  4338. let imgWebs = [
  4339. /<a((?!<a).)*href="https?:\/\/((?!<a).)*imgur.com((?!<a).)*>(((?!<a).)*)<\/a>/g,
  4340. /<a((?!<a).)*href="https?:\/\/((?!<a).)*\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG) ((?!<a).)*>(((?!<a).)*)<\/a>/g
  4341. ];
  4342. imgWebs.map((v, i) => {
  4343. let has = str.matchAll(v);
  4344. let res2 = [...has];
  4345. res2.map((r2) => {
  4346. let p = i === 0 ? r2[4] : r2[5];
  4347. if (p) {
  4348. let link = p.toLowerCase();
  4349. let src = p;
  4350. if (link.includes(".png") || link.includes(".jpg") || link.includes(".jpeg") || link.includes(".gif")) {
  4351. } else {
  4352. src = p + ".png";
  4353. }
  4354. str = str.replace(r2[0], `<img src="${src}" data-originUrl="${p}" data-notice="此img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`);
  4355. }
  4356. });
  4357. });
  4358. } catch (e2) {
  4359. console.log("正则解析html里面的a标签的图片链接出错了");
  4360. }
  4361. return str;
  4362. },
  4363. //检测帖子回复长度
  4364. async checkPostReplies(id, needOpen = true) {
  4365. return new Promise(async (resolve) => {
  4366. var _a;
  4367. let showJsonUrl = `${location.origin}/api/topics/show.json?id=${id}`;
  4368. let r2 = await fetch(showJsonUrl);
  4369. if (r2) {
  4370. let res = await r2.json();
  4371. if (res) {
  4372. if (((_a = res[0]) == null ? void 0 : _a.replies) > MAX_REPLY_LIMIT) {
  4373. if (needOpen) {
  4374. window.parse.openNewTab(`https://www.v2ex.com/t/${id}?p=1&script=1`);
  4375. }
  4376. return resolve(true);
  4377. }
  4378. }
  4379. }
  4380. resolve(false);
  4381. });
  4382. },
  4383. async sleep(time) {
  4384. return new Promise((resolve) => {
  4385. setTimeout(resolve, time);
  4386. });
  4387. },
  4388. //打开新标签页
  4389. openNewTab(href) {
  4390. _GM_openInTab(href, { active: false });
  4391. },
  4392. async cbChecker(val, count = 0) {
  4393. if (window.cb) {
  4394. window.cb(val);
  4395. } else {
  4396. while (!window.cb && count < 30) {
  4397. await functions.sleep(500);
  4398. count++;
  4399. }
  4400. window.cb && window.cb(val);
  4401. }
  4402. },
  4403. //初始化脚本菜单
  4404. initMonkeyMenu() {
  4405. try {
  4406. _GM_registerMenuCommand("脚本设置", () => {
  4407. functions.cbChecker({ type: "openSetting" });
  4408. });
  4409. _GM_registerMenuCommand("仓库地址", () => {
  4410. functions.openNewTab(window.const.git);
  4411. });
  4412. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  4413. } catch (e2) {
  4414. console.error("无法使用Tampermonkey");
  4415. }
  4416. },
  4417. clone(val) {
  4418. return JSON.parse(JSON.stringify(val));
  4419. },
  4420. feedback() {
  4421. functions.openNewTab(DefaultVal.issue);
  4422. }
  4423. };
  4424. const _sfc_main = {
  4425. components: {
  4426. BaseButton,
  4427. NotificationModal,
  4428. BaseLoading,
  4429. BaseSwitch,
  4430. MsgModal,
  4431. TagModal,
  4432. Tooltip,
  4433. Setting,
  4434. PostDetail,
  4435. Base64Tooltip,
  4436. Msg
  4437. },
  4438. provide() {
  4439. return {
  4440. isMobile: vue.computed(() => window.vals.isMobile),
  4441. isLogin: vue.computed(() => this.isLogin),
  4442. isNight: vue.computed(() => this.isNight),
  4443. pageType: vue.computed(() => this.pageType),
  4444. tags: vue.computed(() => this.tags),
  4445. show: vue.computed(() => this.show),
  4446. post: vue.computed(() => this.current),
  4447. config: vue.computed(() => this.config),
  4448. allReplyUsers: vue.computed(() => {
  4449. var _a, _b, _c;
  4450. if ((_a = this.current) == null ? void 0 : _a.replyList) {
  4451. return Array.from(new Set(((_c = (_b = this.current) == null ? void 0 : _b.replyList) == null ? void 0 : _c.map((v) => v.username)) ?? []));
  4452. }
  4453. return [];
  4454. }),
  4455. showConfig: this.showConfig
  4456. };
  4457. },
  4458. data() {
  4459. return {
  4460. loading: window.pageType === PageType.Post,
  4461. refreshLoading: false,
  4462. loadMore: false,
  4463. isLogin: !!window.user.username,
  4464. pageType: window.pageType,
  4465. isNight: window.isNight,
  4466. stopMe: window.stopMe,
  4467. //停止使用脚本
  4468. show: false,
  4469. current: window.clone(window.initPost),
  4470. list: [],
  4471. config: window.clone(window.config),
  4472. tags: window.user.tags,
  4473. readList: window.user.readList,
  4474. configModal: {
  4475. show: false
  4476. },
  4477. notificationModal: {
  4478. show: false,
  4479. h: ""
  4480. }
  4481. };
  4482. },
  4483. computed: {
  4484. targetUserTags() {
  4485. return this.tags[window.targetUserName] ?? [];
  4486. },
  4487. isList() {
  4488. return [PageType.Home, PageType.Node].includes(this.pageType);
  4489. },
  4490. isPost() {
  4491. return this.pageType === PageType.Post;
  4492. },
  4493. isMember() {
  4494. return this.pageType === PageType.Member;
  4495. }
  4496. },
  4497. watch: {
  4498. config: {
  4499. handler(newVal) {
  4500. let config2 = { [window.user.username ?? "default"]: newVal };
  4501. localStorage.setItem("v2ex-config", JSON.stringify(config2));
  4502. window.config = newVal;
  4503. },
  4504. deep: true
  4505. },
  4506. tags(newVal) {
  4507. window.user.tags = newVal;
  4508. },
  4509. "config.viewType"(newVal) {
  4510. if (!newVal)
  4511. return;
  4512. if (newVal === "card") {
  4513. $(".post-item").each(function() {
  4514. $(this).addClass("preview");
  4515. });
  4516. } else {
  4517. $(".post-item").each(function() {
  4518. $(this).removeClass("preview");
  4519. });
  4520. }
  4521. }
  4522. },
  4523. created() {
  4524. let that = this;
  4525. this.initEvent();
  4526. window.cb = this.winCb;
  4527. if (!window.canParseV2exPage)
  4528. return;
  4529. $(document).on("click", "a", this.clickA);
  4530. $(document).on("click", ".post-item", function(e2) {
  4531. if (e2.currentTarget.getAttribute("script"))
  4532. return;
  4533. if (that.stopMe)
  4534. return true;
  4535. if (this.classList.contains("preview")) {
  4536. if (e2.target.tagName !== "A" && e2.target.tagName !== "IMG" && !e2.target.classList.contains("toggle")) {
  4537. console.log("点空白处", this);
  4538. let id = this.dataset["id"];
  4539. let href = this.dataset["href"];
  4540. if (id) {
  4541. that.clickPost(e2, id, href);
  4542. } else {
  4543. if (href)
  4544. location.href = href;
  4545. }
  4546. }
  4547. }
  4548. });
  4549. $(document).on("click", ".toggle", (e2) => {
  4550. if (this.stopMe)
  4551. return true;
  4552. let id = e2.currentTarget.dataset["id"];
  4553. let itemDom = window.win().query(`.id_${id}`);
  4554. if (itemDom.classList.contains("preview")) {
  4555. itemDom.classList.remove("preview");
  4556. } else {
  4557. itemDom.classList.add("preview");
  4558. }
  4559. });
  4560. window.onpopstate = (event) => {
  4561. if (event.state) {
  4562. if (!this.show)
  4563. this.show = true;
  4564. } else {
  4565. if (this.show)
  4566. this.show = false;
  4567. }
  4568. };
  4569. window.onbeforeunload = () => {
  4570. };
  4571. window.deleteNotification = (nId, token) => {
  4572. console.log("deleteNotification", nId, token);
  4573. let item = $("#n_" + nId);
  4574. item.slideUp("fast");
  4575. $.post({
  4576. url: "/delete/notification/" + nId + "?once=" + token,
  4577. success() {
  4578. $.get({
  4579. url: "/notifications/below/" + window.notificationBottom,
  4580. success(data, status, request) {
  4581. item.remove();
  4582. $("#notifications").append(data);
  4583. window.notificationBottom = request.getResponseHeader("X-V2EX-New-Notification-Bottom");
  4584. },
  4585. error() {
  4586. item.slideDown("fast");
  4587. }
  4588. });
  4589. },
  4590. error() {
  4591. item.slideDown("fast");
  4592. }
  4593. });
  4594. };
  4595. },
  4596. beforeUnmount() {
  4597. eventBus.clear();
  4598. $(document).off("click", "a", this.clickA);
  4599. },
  4600. methods: {
  4601. async getUnreadMessagesCount() {
  4602. var _a, _b;
  4603. const res = await fetch(`${location.origin}/mission`);
  4604. const htmlText = await res.text();
  4605. const $page = $(htmlText);
  4606. const text = $page.find('#Rightbar a[href^="/notifications"]').text();
  4607. if (text.includes("未读提醒")) {
  4608. const countStr = (_a = text.match(/\d+/)) == null ? void 0 : _a.at(0);
  4609. if (countStr) {
  4610. return Number((_b = text.match(/\d+/)) == null ? void 0 : _b.at(0));
  4611. }
  4612. } else {
  4613. return 0;
  4614. }
  4615. throw new Error("无法获取未读消息数量");
  4616. },
  4617. clickA(e2) {
  4618. let that = this;
  4619. if (e2.currentTarget.getAttribute("script"))
  4620. return;
  4621. if (that.stopMe)
  4622. return true;
  4623. let { href, id, title } = window.parse.parseA(e2.currentTarget);
  4624. console.log("click-a", e2.currentTarget, e2, href, id, title);
  4625. if (href.includes("/settings/night/toggle"))
  4626. return;
  4627. if (href.includes("/?tab="))
  4628. return;
  4629. if (href.includes("/go"))
  4630. return;
  4631. if (href === window.origin + "/#;")
  4632. return;
  4633. if (href === window.origin + "/")
  4634. return;
  4635. if (href.includes("/notifications"))
  4636. ;
  4637. if (id) {
  4638. that.clickPost(e2, id, href, title);
  4639. } else {
  4640. if (that.config.newTabOpen) {
  4641. that.stopEvent(e2);
  4642. functions.openNewTab(href);
  4643. }
  4644. }
  4645. },
  4646. stopEvent(e2) {
  4647. e2.preventDefault();
  4648. e2.stopPropagation();
  4649. },
  4650. saveReadList() {
  4651. if (this.config.rememberLastReadFloor) {
  4652. window.parse.saveReadList(this.readList);
  4653. }
  4654. },
  4655. async clickPost(e2, id, href, title = "") {
  4656. if (id) {
  4657. if (this.config.clickPostItemOpenDetail) {
  4658. this.stopEvent(e2);
  4659. let index = this.list.findIndex((v) => v.id == id);
  4660. let postItem = this.clone(window.initPost);
  4661. if (index > -1) {
  4662. postItem = this.list[index];
  4663. }
  4664. if (!postItem.title) {
  4665. postItem.title = title ?? "加载中";
  4666. }
  4667. postItem.inList = index > -1;
  4668. if (postItem.inList) {
  4669. if (postItem.replyCount > MAX_REPLY_LIMIT) {
  4670. return functions.openNewTab(`${location.origin}/t/${id}?p=1&script=1`);
  4671. }
  4672. }
  4673. postItem.id = id;
  4674. postItem.href = href;
  4675. if (!postItem.headerTemplate) {
  4676. let template = `
  4677. <div class="cell">
  4678. <div class="topic_content">
  4679. <div class="markdown_body">
  4680. ${(postItem == null ? void 0 : postItem.content_rendered) ?? ""}
  4681. </div>
  4682. </div>
  4683. </div>
  4684. `;
  4685. postItem.headerTemplate = template;
  4686. }
  4687. this.getPostDetail(postItem);
  4688. return;
  4689. }
  4690. if (this.config.newTabOpen) {
  4691. this.stopEvent(e2);
  4692. functions.openNewTab(`https://www.v2ex.com/t/${id}?p=1`);
  4693. }
  4694. }
  4695. },
  4696. showPost() {
  4697. this.show = true;
  4698. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  4699. $(this).hide();
  4700. });
  4701. },
  4702. showConfig() {
  4703. this.configModal.show = true;
  4704. },
  4705. async winCb({ type, value }) {
  4706. if (type === "openSetting") {
  4707. this.showConfig();
  4708. }
  4709. if (type === "syncData") {
  4710. this.list = window.postList;
  4711. this.config = window.config;
  4712. this.stopMe = window.stopMe;
  4713. this.tags = window.user.tags;
  4714. this.readList = window.user.readList;
  4715. this.current.read = this.readList[this.current.id] ?? {};
  4716. if (this.show && this.isPost && this.current.read.floor) {
  4717. this.$refs.postDetail.read = this.current.read;
  4718. }
  4719. }
  4720. if (type === "warningNotice") {
  4721. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: value });
  4722. }
  4723. if (this.stopMe)
  4724. return;
  4725. if (type === "restorePost") {
  4726. this.show = false;
  4727. this.loading = false;
  4728. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "脚本无法查看此页面!" });
  4729. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  4730. $(this).show();
  4731. });
  4732. }
  4733. if (type === "postContent") {
  4734. this.current = Object.assign(this.current, value);
  4735. this.current.inList = true;
  4736. if (this.config.autoOpenDetail) {
  4737. this.showPost();
  4738. }
  4739. }
  4740. if (type === "postReplies") {
  4741. this.current = Object.assign(this.current, value);
  4742. this.list.push(this.clone(this.current));
  4743. this.loading = false;
  4744. }
  4745. },
  4746. clone(val) {
  4747. return window.clone(val);
  4748. },
  4749. regenerateReplyList() {
  4750. if (this.current.replyList.length) {
  4751. this.current.replyCount = this.current.replyList.length;
  4752. let res = window.parse.createNestedList(this.current.replyList);
  4753. if (res) {
  4754. this.current.nestedReplies = res;
  4755. }
  4756. let dup_res = window.parse.createNestedRedundantList(this.current.replyList);
  4757. if (dup_res) {
  4758. this.current.nestedRedundReplies = dup_res;
  4759. }
  4760. } else {
  4761. this.current.replyCount = 0;
  4762. this.current.nestedReplies = [];
  4763. this.current.nestedRedundReplies = [];
  4764. }
  4765. if (this.list.length) {
  4766. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  4767. if (rIndex > -1) {
  4768. this.list[rIndex] = this.clone(this.current);
  4769. }
  4770. }
  4771. },
  4772. initEvent() {
  4773. eventBus.on(CMD.CHANGE_COMMENT_THANK, (val) => {
  4774. console.log("CHANGE_COMMENT_THANK", val);
  4775. const { id, type } = val;
  4776. let currentI = this.current.replyList.findIndex((i) => i.id === id);
  4777. if (currentI > -1) {
  4778. this.current.replyList[currentI].isThanked = type === "add";
  4779. if (type === "add") {
  4780. this.current.replyList[currentI].thankCount++;
  4781. } else {
  4782. this.current.replyList[currentI].thankCount--;
  4783. }
  4784. this.regenerateReplyList();
  4785. }
  4786. });
  4787. eventBus.on(CMD.CHANGE_POST_THANK, (val) => {
  4788. const { id, type } = val;
  4789. this.current.isThanked = type === "add";
  4790. if (type === "add") {
  4791. this.current.thankCount++;
  4792. } else {
  4793. this.current.thankCount--;
  4794. }
  4795. let currentI = this.list.findIndex((i) => i.id === id);
  4796. if (currentI > -1) {
  4797. this.list[currentI].isThanked = type === "add";
  4798. if (type === "add") {
  4799. this.list[currentI].thankCount++;
  4800. } else {
  4801. this.list[currentI].thankCount++;
  4802. }
  4803. }
  4804. });
  4805. eventBus.on(CMD.REMOVE, (val) => {
  4806. let removeIndex = this.current.replyList.findIndex((i) => i.floor === val);
  4807. if (removeIndex > -1) {
  4808. this.current.replyList.splice(removeIndex, 1);
  4809. }
  4810. this.regenerateReplyList();
  4811. });
  4812. eventBus.on(CMD.IGNORE, () => {
  4813. this.show = false;
  4814. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  4815. if (rIndex > -1) {
  4816. this.list.splice(rIndex, 1);
  4817. }
  4818. this.current = this.clone(window.initPost);
  4819. });
  4820. eventBus.on(CMD.MERGE, (val) => {
  4821. this.current = Object.assign(this.current, val);
  4822. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  4823. if (rIndex > -1) {
  4824. this.list[rIndex] = this.clone(this.current);
  4825. }
  4826. });
  4827. eventBus.on(CMD.ADD_READ, (val) => {
  4828. this.readList[this.current.id] = val;
  4829. });
  4830. eventBus.on(CMD.ADD_REPLY, (item) => {
  4831. this.current.replyList.push(item);
  4832. this.regenerateReplyList();
  4833. });
  4834. eventBus.on(CMD.REFRESH_ONCE, async (once) => {
  4835. if (once) {
  4836. if (typeof once === "string") {
  4837. let res = once.match(/var once = "([\d]+)";/);
  4838. if (res && res[1]) {
  4839. this.current.once = Number(res[1]);
  4840. return;
  4841. }
  4842. }
  4843. if (typeof once === "number") {
  4844. this.current.once = once;
  4845. return;
  4846. }
  4847. }
  4848. window.fetchOnce().then((r2) => {
  4849. this.current.once = r2;
  4850. });
  4851. });
  4852. eventBus.on(CMD.REMOVE_TAG, async ({ username, tag }) => {
  4853. let oldTag = this.clone(this.tags);
  4854. let tags = this.tags[username] ?? [];
  4855. let rIndex = tags.findIndex((v) => v === tag);
  4856. if (rIndex > -1) {
  4857. tags.splice(rIndex, 1);
  4858. }
  4859. this.tags[username] = tags;
  4860. let res = await window.parse.saveTags(this.tags);
  4861. if (!res) {
  4862. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签删除失败!" });
  4863. this.tags = oldTag;
  4864. }
  4865. });
  4866. eventBus.on(CMD.REFRESH_POST, () => this.getPostDetail(this.current));
  4867. },
  4868. async getPostDetail(post) {
  4869. this.current = post;
  4870. this.current.read = this.readList[this.current.id] ?? { floor: 0, total: 0 };
  4871. this.show = true;
  4872. if (!this.current.inList) {
  4873. this.loading = true;
  4874. let r2 = await window.parse.checkPostReplies(post.id, true);
  4875. if (r2) {
  4876. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "由于回复数量较多,已为您单独打开此主题" });
  4877. this.loading = this.show = false;
  4878. return;
  4879. }
  4880. }
  4881. let url = window.baseUrl + "/t/" + post.id;
  4882. this.current.url = url;
  4883. let alreadyHasReply = this.current.replyList.length;
  4884. if (alreadyHasReply) {
  4885. this.refreshLoading = true;
  4886. this.$refs.postDetail.jumpLastRead(this.current.read.floor);
  4887. } else {
  4888. this.loading = true;
  4889. }
  4890. let apiRes = await window.fetch(url + "?p=1");
  4891. if (apiRes.status === 404) {
  4892. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "主题未找到" });
  4893. return this.refreshLoading = this.loading = false;
  4894. }
  4895. if (apiRes.status === 403) {
  4896. this.refreshLoading = this.show = this.loading = false;
  4897. functions.openNewTab(`${location.origin}/t/${post.id}?p=1&script=0`);
  4898. return;
  4899. }
  4900. if (apiRes.redirected) {
  4901. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有权限" });
  4902. return this.refreshLoading = this.loading = false;
  4903. }
  4904. let htmlText = await apiRes.text();
  4905. let hasPermission = htmlText.search("你要查看的页面需要先登录");
  4906. if (hasPermission > -1) {
  4907. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你要查看的页面需要先登录" });
  4908. return this.refreshLoading = this.loading = false;
  4909. }
  4910. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  4911. let body = $(bodyText[0]);
  4912. decodeEmail(body);
  4913. await window.parse.getPostDetail(this.current, body, htmlText);
  4914. let index = this.list.findIndex((v) => v.id == this.current.id);
  4915. if (index > -1) {
  4916. this.list[index] = this.clone(this.current);
  4917. } else {
  4918. this.list.push(this.clone(this.current));
  4919. }
  4920. this.refreshLoading = this.loading = false;
  4921. if (!alreadyHasReply) {
  4922. vue.nextTick(() => {
  4923. this.$refs.postDetail.jumpLastRead(this.current.read.floor);
  4924. });
  4925. }
  4926. await window.parse.parseOp(this.current);
  4927. console.log("当前帖子", this.current);
  4928. },
  4929. addTargetUserTag() {
  4930. eventBus.emit(CMD.ADD_TAG, window.targetUserName);
  4931. },
  4932. removeTargetUserTag(tag) {
  4933. eventBus.emit(CMD.REMOVE_TAG, { username: window.targetUserName, tag });
  4934. }
  4935. }
  4936. };
  4937. const _withScopeId = (n2) => (vue.pushScopeId("data-v-6c0e87a5"), n2 = n2(), vue.popScopeId(), n2);
  4938. const _hoisted_1 = {
  4939. key: 0,
  4940. class: "target-user-tags p1"
  4941. };
  4942. const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "标签:", -1));
  4943. const _hoisted_3 = { class: "my-tag" };
  4944. const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  4945. const _hoisted_5 = ["onClick"];
  4946. const _hoisted_6 = {
  4947. key: 1,
  4948. class: "my-box p2",
  4949. style: { "margin-top": "2rem" }
  4950. };
  4951. const _hoisted_7 = {
  4952. key: 0,
  4953. class: "flex flex-center"
  4954. };
  4955. const _hoisted_8 = {
  4956. key: 1,
  4957. class: "loaded"
  4958. };
  4959. const _hoisted_9 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "楼中楼解析完成", -1));
  4960. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  4961. const _component_Setting = vue.resolveComponent("Setting");
  4962. const _component_TagModal = vue.resolveComponent("TagModal");
  4963. const _component_PostDetail = vue.resolveComponent("PostDetail");
  4964. const _component_Base64Tooltip = vue.resolveComponent("Base64Tooltip");
  4965. const _component_MsgModal = vue.resolveComponent("MsgModal");
  4966. const _component_NotificationModal = vue.resolveComponent("NotificationModal");
  4967. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  4968. const _component_BaseButton = vue.resolveComponent("BaseButton");
  4969. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  4970. vue.createVNode(_component_Setting, {
  4971. modelValue: $data.config,
  4972. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.config = $event),
  4973. show: $data.configModal.show,
  4974. "onUpdate:show": _cache[1] || (_cache[1] = ($event) => $data.configModal.show = $event)
  4975. }, null, 8, ["modelValue", "show"]),
  4976. vue.createVNode(_component_TagModal, {
  4977. tags: $data.tags,
  4978. "onUpdate:tags": _cache[2] || (_cache[2] = ($event) => $data.tags = $event)
  4979. }, null, 8, ["tags"]),
  4980. vue.createVNode(_component_PostDetail, {
  4981. modelValue: $data.show,
  4982. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.show = $event),
  4983. ref: "postDetail",
  4984. displayType: $data.config.commentDisplayType,
  4985. "onUpdate:displayType": _cache[4] || (_cache[4] = ($event) => $data.config.commentDisplayType = $event),
  4986. onSaveReadList: $options.saveReadList,
  4987. onRefresh: _cache[5] || (_cache[5] = ($event) => $options.getPostDetail($data.current)),
  4988. loading: $data.loading,
  4989. refreshLoading: $data.refreshLoading
  4990. }, null, 8, ["modelValue", "displayType", "onSaveReadList", "loading", "refreshLoading"]),
  4991. vue.createVNode(_component_Base64Tooltip),
  4992. vue.createVNode(_component_MsgModal),
  4993. vue.createVNode(_component_NotificationModal, {
  4994. modelValue: $data.notificationModal.show,
  4995. "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => $data.notificationModal.show = $event),
  4996. h: $data.notificationModal.h
  4997. }, null, 8, ["modelValue", "h"]),
  4998. !$data.stopMe ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  4999. $options.isMember && $data.isLogin && $data.config.openTag ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
  5000. _hoisted_2,
  5001. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.targetUserTags, (i) => {
  5002. return vue.openBlock(), vue.createElementBlock("span", _hoisted_3, [
  5003. _hoisted_4,
  5004. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  5005. vue.createElementVNode("i", {
  5006. class: "fa fa-trash-o remove",
  5007. onClick: ($event) => $options.removeTargetUserTag(i)
  5008. }, null, 8, _hoisted_5)
  5009. ]);
  5010. }), 256)),
  5011. vue.createElementVNode("span", {
  5012. class: "add-tag ago",
  5013. onClick: _cache[7] || (_cache[7] = (...args) => $options.addTargetUserTag && $options.addTargetUserTag(...args)),
  5014. title: "添加标签"
  5015. }, "+")
  5016. ])) : vue.createCommentVNode("", true),
  5017. $options.isPost && !$data.show && $data.config.autoOpenDetail ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6, [
  5018. $data.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [
  5019. vue.createVNode(_component_BaseLoading)
  5020. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_8, [
  5021. _hoisted_9,
  5022. vue.createVNode(_component_BaseButton, {
  5023. size: "small",
  5024. onClick: $options.showPost
  5025. }, {
  5026. default: vue.withCtx(() => [
  5027. vue.createTextVNode("点击显示")
  5028. ]),
  5029. _: 1
  5030. }, 8, ["onClick"])
  5031. ]))
  5032. ])) : vue.createCommentVNode("", true)
  5033. ], 64)) : vue.createCommentVNode("", true)
  5034. ], 64);
  5035. }
  5036. const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-6c0e87a5"]]);
  5037. let isMobile = !document.querySelector("#Rightbar");
  5038. let $section = document.createElement("section");
  5039. $section.id = "app";
  5040. function run() {
  5041. window.baseUrl = location.origin;
  5042. window.initPost = DefaultPost;
  5043. window.win = function() {
  5044. return window;
  5045. };
  5046. window.win().doc = window.win().document;
  5047. window.win().query = (v) => window.win().document.querySelector(v);
  5048. window.query = (v) => window.win().document.querySelector(v);
  5049. window.clone = (val) => JSON.parse(JSON.stringify(val));
  5050. window.user = DefaultUser;
  5051. window.targetUserName = "";
  5052. window.pageType = void 0;
  5053. window.pageData = { pageNo: 1 };
  5054. window.config = DefaultConfig;
  5055. window.const = {
  5056. git: "https://github.com/zyronon/v2ex-script",
  5057. issue: "https://github.com/zyronon/v2ex-script/issues"
  5058. };
  5059. window.currentVersion = 1;
  5060. window.isNight = $(".Night").length === 1;
  5061. window.cb = null;
  5062. window.stopMe = false;
  5063. window.postList = [];
  5064. window.parse = {
  5065. //解析帖子内容
  5066. async parsePostContent(post, body, htmlText) {
  5067. let once = htmlText.match(/var once = "([\d]+)";/);
  5068. if (once && once[1]) {
  5069. post.once = once[1];
  5070. }
  5071. post.isReport = htmlText.includes("你已对本主题进行了报告");
  5072. let wrapper = body.find("#Main");
  5073. if (!post.title || !post.content_rendered) {
  5074. let h1 = wrapper.find("h1");
  5075. if (h1) {
  5076. post.title = h1[0].innerText;
  5077. }
  5078. }
  5079. let as = wrapper.find(".header > a");
  5080. if (as.length) {
  5081. post.node.title = as[1].innerText;
  5082. post.node.url = as[1].href;
  5083. }
  5084. let aName = wrapper.find(".header small.gray a:nth-child(1)");
  5085. if (aName) {
  5086. post.member.username = aName[0].innerText;
  5087. }
  5088. let spanEl = wrapper.find(".header small.gray span");
  5089. if (spanEl) {
  5090. post.createDateAgo = spanEl[0].innerText;
  5091. }
  5092. let avatarEl = wrapper.find(".header .avatar");
  5093. if (avatarEl) {
  5094. post.member.avatar_large = avatarEl[0].src;
  5095. }
  5096. let topic_buttons = body.find(".topic_buttons");
  5097. if (topic_buttons.length) {
  5098. let favoriteNode = topic_buttons.find(".tb:first");
  5099. if (favoriteNode.length) {
  5100. post.isFavorite = favoriteNode[0].innerText === "取消收藏";
  5101. }
  5102. let ignoreNode = topic_buttons.find(".tb:nth-child(3)");
  5103. if (ignoreNode.length) {
  5104. post.isIgnore = ignoreNode[0].innerText === "取消忽略";
  5105. }
  5106. let thankNode = topic_buttons.find("#topic_thank .tb");
  5107. if (!thankNode.length) {
  5108. post.isThanked = true;
  5109. }
  5110. let topic_stats = topic_buttons.find(".topic_stats");
  5111. if (topic_stats.length) {
  5112. let text = topic_stats[0].innerText;
  5113. let reg1 = text.matchAll(/([\d]+)[\s]*人收藏/g);
  5114. let collectCountReg = [...reg1];
  5115. if (collectCountReg.length) {
  5116. post.collectCount = Number(collectCountReg[0][1]);
  5117. }
  5118. reg1 = text.matchAll(/([\d]+)[\s]*likes/g);
  5119. collectCountReg = [...reg1];
  5120. if (collectCountReg.length) {
  5121. post.collectCount = Number(collectCountReg[0][1]);
  5122. }
  5123. let reg2 = text.matchAll(/([\d]+)[\s]*人感谢/g);
  5124. let thankCountReg = [...reg2];
  5125. if (thankCountReg.length) {
  5126. post.thankCount = Number(thankCountReg[0][1]);
  5127. }
  5128. let reg3 = text.matchAll(/([\d]+)[\s]*次点击/g);
  5129. let clickCountReg = [...reg3];
  5130. if (clickCountReg.length) {
  5131. post.clickCount = Number(clickCountReg[0][1]);
  5132. }
  5133. reg3 = text.matchAll(/([\d]+)[\s]*views/g);
  5134. clickCountReg = [...reg3];
  5135. if (clickCountReg.length) {
  5136. post.clickCount = Number(clickCountReg[0][1]);
  5137. }
  5138. }
  5139. }
  5140. let header = body.find(`#Main .box`).first();
  5141. let temp = header.clone();
  5142. temp.find(".topic_buttons").remove();
  5143. temp.find(".inner").remove();
  5144. temp.find(".header").remove();
  5145. let html = temp.html();
  5146. html = this.checkPhotoLink2Img(html);
  5147. post.headerTemplate = html;
  5148. return post;
  5149. },
  5150. //解析OP信息
  5151. async parseOp(post) {
  5152. if (!post.member.id) {
  5153. let userRes = await fetch(window.baseUrl + "/api/members/show.json?username=" + post.member.username);
  5154. if (userRes.status === 200) {
  5155. post.member = await userRes.json();
  5156. }
  5157. }
  5158. if (post.member.id) {
  5159. let date = new Date(post.member.created * 1e3);
  5160. let createStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
  5161. date.setHours(0);
  5162. date.setMinutes(0);
  5163. date.setSeconds(0);
  5164. date.setMilliseconds(0);
  5165. let now = /* @__PURE__ */ new Date();
  5166. now.setHours(0);
  5167. now.setMinutes(0);
  5168. now.setSeconds(0);
  5169. now.setMilliseconds(0);
  5170. let d2 = now.getTime() - date.getTime();
  5171. let isNew = d2 <= 1e3 * 60 * 60 * 24 * 7;
  5172. post.member.createDate = createStr + " 注册";
  5173. post.member.isNew = isNew;
  5174. } else {
  5175. post.member.createDate = "用户已被注销/封禁";
  5176. post.member.isNew = true;
  5177. }
  5178. return post;
  5179. },
  5180. //获取帖子所有回复
  5181. async getPostAllReplies(post, body, htmlText, pageNo = 1) {
  5182. var _a, _b;
  5183. if (body.find("#no-comments-yet").length) {
  5184. return post;
  5185. }
  5186. console.log("body", body);
  5187. let boxs = body.find(`#Main .box`);
  5188. let box = boxs[1];
  5189. console.log("box", box);
  5190. let cells = box.querySelectorAll(".cell");
  5191. if (cells && cells.length) {
  5192. post.fr = cells[0].querySelector(".cell .fr").innerHTML;
  5193. cells = Array.from(cells);
  5194. let snow = cells[0].querySelector(".snow");
  5195. post.createDate = ((_b = (_a = snow == null ? void 0 : snow.nextSibling) == null ? void 0 : _a.nodeValue) == null ? void 0 : _b.trim()) || "";
  5196. let repliesMap = [];
  5197. if (cells[1].id) {
  5198. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(1)) });
  5199. let replyList = this.getAllReply(repliesMap);
  5200. post.replyList = replyList;
  5201. post.replyCount = replyList.length;
  5202. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  5203. let nestedList = this.createNestedList(replyList);
  5204. let nestedRedundantList = this.createNestedRedundantList(replyList);
  5205. if (nestedList)
  5206. post.nestedReplies = nestedList;
  5207. if (nestedRedundantList)
  5208. post.nestedRedundReplies = nestedRedundantList;
  5209. return post;
  5210. } else {
  5211. let promiseList = [];
  5212. return new Promise((resolve, reject) => {
  5213. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  5214. let pages = cells[1].querySelectorAll("a.page_normal");
  5215. pages = Array.from(pages);
  5216. let url = window.baseUrl + "/t/" + post.id;
  5217. for (let i = 0; i < pages.length; i++) {
  5218. let currentPageNo = Number(pages[i].innerText);
  5219. promiseList.push(this.fetchPostOtherPageReplies(url + "?p=" + currentPageNo, currentPageNo));
  5220. }
  5221. Promise.allSettled(promiseList).then(
  5222. (results) => {
  5223. results.filter((result) => result.status === "fulfilled").map((v) => repliesMap.push(v.value));
  5224. let replyList = this.getAllReply(repliesMap);
  5225. post.replyList = replyList;
  5226. post.replyCount = replyList.length;
  5227. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  5228. let nestedList = this.createNestedList(replyList);
  5229. let nestedRedundantList = this.createNestedRedundantList(replyList);
  5230. if (nestedList)
  5231. post.nestedReplies = nestedList;
  5232. if (nestedRedundantList)
  5233. post.nestedRedundReplies = nestedRedundantList;
  5234. resolve(post);
  5235. }
  5236. );
  5237. });
  5238. }
  5239. }
  5240. },
  5241. //请求帖子其他页的回复
  5242. fetchPostOtherPageReplies(href, pageNo) {
  5243. return new Promise((resolve) => {
  5244. $.get(href).then((res) => {
  5245. let s = res.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  5246. let box = $(s[0]).find("#Main .box")[1];
  5247. let cells = box.querySelectorAll(".cell");
  5248. cells = Array.from(cells);
  5249. resolve({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  5250. }).catch((r2) => {
  5251. if (r2.status === 403) {
  5252. cbChecker({ type: "restorePost", value: null });
  5253. }
  5254. });
  5255. });
  5256. },
  5257. //解析页面的回复
  5258. parsePageReplies(nodes) {
  5259. let replyList = [];
  5260. nodes.forEach((node, index) => {
  5261. if (!node.id)
  5262. return;
  5263. let item = {
  5264. level: 0,
  5265. thankCount: 0,
  5266. isThanked: false,
  5267. isOp: false,
  5268. isDup: false,
  5269. id: node.id.replace("r_", "")
  5270. };
  5271. let reply_content = node.querySelector(".reply_content");
  5272. item.reply_content = this.checkPhotoLink2Img(reply_content.innerHTML);
  5273. item.reply_text = reply_content.textContent;
  5274. let { users, floor } = this.parseReplyContent(item.reply_content);
  5275. item.hideCallUserReplyContent = item.reply_content;
  5276. if (users.length === 1) {
  5277. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(\s#[\d]+)?\s(<br>)?/, () => "");
  5278. }
  5279. item.replyUsers = users;
  5280. item.replyFloor = floor;
  5281. let ago = node.querySelector(".ago");
  5282. item.date = ago.textContent;
  5283. let userNode = node.querySelector("strong a");
  5284. item.username = userNode.textContent;
  5285. let avatar = node.querySelector("td img");
  5286. item.avatar = avatar.src;
  5287. let no = node.querySelector(".no");
  5288. item.floor = Number(no.textContent);
  5289. let thank_area = node.querySelector(".thank_area");
  5290. if (thank_area) {
  5291. item.isThanked = thank_area.classList.contains("thanked");
  5292. }
  5293. let small = node.querySelector(".small");
  5294. if (small) {
  5295. item.thankCount = Number(small.textContent);
  5296. }
  5297. let op = node.querySelector(".op");
  5298. if (op) {
  5299. item.isOp = true;
  5300. }
  5301. let mod = node.querySelector(".mod");
  5302. if (mod) {
  5303. item.isMod = true;
  5304. }
  5305. replyList.push(item);
  5306. });
  5307. return replyList;
  5308. },
  5309. //解析回复内容,解析出@用户,回复楼层。用于后续生成嵌套楼层
  5310. parseReplyContent(str) {
  5311. if (!str)
  5312. return;
  5313. let users = [];
  5314. let getUsername = (userStr) => {
  5315. let endIndex = userStr.indexOf('">');
  5316. if (endIndex > -1) {
  5317. let user = userStr.substring(0, endIndex);
  5318. if (!users.find((i) => i === user)) {
  5319. users.push(user);
  5320. }
  5321. }
  5322. };
  5323. let userReg = /@<a href="\/member\/([\s\S]+?)<\/a>/g;
  5324. let has = str.matchAll(userReg);
  5325. let res2 = [...has];
  5326. if (res2.length > 1) {
  5327. res2.map((item) => {
  5328. getUsername(item[1]);
  5329. });
  5330. }
  5331. if (res2.length === 1) {
  5332. getUsername(res2[0][1]);
  5333. }
  5334. let floor = -1;
  5335. if (users.length === 1) {
  5336. let floorReg = /@<a href="\/member\/[\s\S]+?<\/a>[\s]+#([\d]+)/g;
  5337. let hasFloor = str.matchAll(floorReg);
  5338. let res = [...hasFloor];
  5339. if (res.length) {
  5340. floor = Number(res[0][1]);
  5341. }
  5342. }
  5343. return { users, floor };
  5344. },
  5345. //获取帖子详情
  5346. async getPostDetail(post, body, htmlText, pageNo = 1) {
  5347. post = await this.parsePostContent(post, body, htmlText);
  5348. return await this.getPostAllReplies(post, body, htmlText, pageNo);
  5349. },
  5350. //获取所有回复
  5351. getAllReply(repliesMap = []) {
  5352. return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
  5353. pre = pre.concat(i.replyList);
  5354. return pre;
  5355. }, []);
  5356. },
  5357. //生成嵌套回复
  5358. createNestedList(allList = []) {
  5359. if (!allList.length)
  5360. return [];
  5361. let list = window.clone(allList);
  5362. let nestedList = [];
  5363. list.map((item, index) => {
  5364. let startList = list.slice(0, index);
  5365. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  5366. let endList = list.slice(index + 1);
  5367. if (index === 0) {
  5368. nestedList.push(this.findChildren(item, endList, list));
  5369. } else {
  5370. if (!item.isUse) {
  5371. let isOneLevelReply = false;
  5372. if (item.replyUsers.length) {
  5373. if (item.replyUsers.length > 1) {
  5374. isOneLevelReply = true;
  5375. } else {
  5376. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  5377. }
  5378. } else {
  5379. isOneLevelReply = true;
  5380. }
  5381. if (isOneLevelReply) {
  5382. item.level = 0;
  5383. nestedList.push(this.findChildren(item, endList, list));
  5384. }
  5385. }
  5386. }
  5387. });
  5388. return nestedList;
  5389. },
  5390. //生成嵌套冗余回复
  5391. createNestedRedundantList(allList = []) {
  5392. if (!allList.length)
  5393. return [];
  5394. let list = window.clone(allList);
  5395. let nestedList = [];
  5396. list.map((item, index) => {
  5397. let startList = list.slice(0, index);
  5398. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  5399. let endList = list.slice(index + 1);
  5400. if (index === 0) {
  5401. nestedList.push(this.findChildren(item, endList, list));
  5402. } else {
  5403. if (!item.isUse) {
  5404. let isOneLevelReply = false;
  5405. if (item.replyUsers.length) {
  5406. if (item.replyUsers.length > 1) {
  5407. isOneLevelReply = true;
  5408. } else {
  5409. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  5410. }
  5411. } else {
  5412. isOneLevelReply = true;
  5413. }
  5414. if (isOneLevelReply) {
  5415. item.level = 0;
  5416. nestedList.push(this.findChildren(item, endList, list));
  5417. }
  5418. } else {
  5419. let newItem = window.clone(item);
  5420. newItem.children = [];
  5421. newItem.level = 0;
  5422. newItem.isDup = true;
  5423. nestedList.push(newItem);
  5424. }
  5425. }
  5426. });
  5427. return nestedList;
  5428. },
  5429. //查找子回复
  5430. findChildren(item, endList, all) {
  5431. var _a;
  5432. const fn = (child, endList2, parent) => {
  5433. child.level = parent.level + 1;
  5434. let rIndex = all.findIndex((v) => v.floor === child.floor);
  5435. if (rIndex > -1) {
  5436. all[rIndex].isUse = true;
  5437. }
  5438. parent.children.push(this.findChildren(child, endList2, all));
  5439. };
  5440. item.children = [];
  5441. let floorReplyList = [];
  5442. for (let i = 0; i < endList.length; i++) {
  5443. let currentItem = endList[i];
  5444. if (currentItem.isUse)
  5445. continue;
  5446. if (currentItem.replyFloor === item.floor) {
  5447. if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
  5448. currentItem.isUse = true;
  5449. floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
  5450. } else {
  5451. currentItem.isWrong = true;
  5452. }
  5453. }
  5454. }
  5455. floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
  5456. fn(currentItem, endList2, item);
  5457. });
  5458. let nextMeIndex = endList.findIndex((v) => {
  5459. var _a2;
  5460. return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
  5461. });
  5462. let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
  5463. for (let i = 0; i < findList.length; i++) {
  5464. let currentItem = findList[i];
  5465. if (currentItem.isUse)
  5466. continue;
  5467. if (currentItem.replyUsers.length === 1) {
  5468. if (currentItem.replyFloor !== -1) {
  5469. if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
  5470. continue;
  5471. }
  5472. }
  5473. let endList2 = endList.slice(i + 1);
  5474. if (currentItem.username === item.username) {
  5475. if (currentItem.replyUsers[0] === item.username) {
  5476. fn(currentItem, endList2, item);
  5477. }
  5478. break;
  5479. } else {
  5480. if (currentItem.replyUsers[0] === item.username) {
  5481. fn(currentItem, endList2, item);
  5482. }
  5483. }
  5484. } else {
  5485. if (currentItem.username === item.username)
  5486. break;
  5487. }
  5488. }
  5489. item.children = item.children.sort((a, b) => a.floor - b.floor);
  5490. return item;
  5491. },
  5492. //解析页面帖子列表
  5493. parsePagePostList(list, box) {
  5494. list.forEach((itemDom) => {
  5495. let item = window.clone(window.initPost);
  5496. let item_title = itemDom.querySelector(".item_title a");
  5497. let { href, id } = window.parse.parseA(item_title);
  5498. item.id = id;
  5499. item.href = href;
  5500. item.url = location.origin + "/api/topics/show.json?id=" + item.id;
  5501. itemDom.classList.add("post-item");
  5502. itemDom.classList.add(`id_${id}`);
  5503. itemDom.dataset["href"] = href;
  5504. itemDom.dataset["id"] = id;
  5505. window.postList.push(item);
  5506. });
  5507. Promise.allSettled(window.postList.map((item) => $.get(item.url))).then((res) => {
  5508. let ok = res.filter((r2) => r2.status === "fulfilled").map((v) => v.value[0]);
  5509. box.style.boxShadow = "unset";
  5510. box.style.background = "unset";
  5511. if (window.config.viewType === "card") {
  5512. list.forEach((itemDom) => itemDom.classList.add("preview"));
  5513. }
  5514. ok.map((postItem) => {
  5515. var _a;
  5516. if (postItem == null ? void 0 : postItem.id) {
  5517. let itemDom = box.querySelector(`.id_${postItem.id}`);
  5518. if (window.config.showPreviewBtn) {
  5519. let td = itemDom.querySelector("td:nth-child(4)");
  5520. td.style.position = "relative";
  5521. let toggle = document.createElement("div");
  5522. toggle.dataset["id"] = postItem.id;
  5523. toggle.classList.add("toggle");
  5524. toggle.innerText = "点击展开/收起";
  5525. td.append(toggle);
  5526. }
  5527. let index = window.postList.findIndex((v) => v.id == postItem.id);
  5528. if (index > -1) {
  5529. let obj = window.postList[index];
  5530. postItem.replyCount = postItem.replies;
  5531. window.postList[index] = Object.assign({}, obj, postItem);
  5532. if (postItem.content_rendered) {
  5533. let a = document.createElement("a");
  5534. a.href = obj.href;
  5535. a.classList.add("post-content");
  5536. let div = document.createElement("div");
  5537. div.innerHTML = postItem.content_rendered;
  5538. a.append(div);
  5539. itemDom.append(a);
  5540. if (div.clientHeight < 172) {
  5541. a.classList.add("show-all");
  5542. } else {
  5543. let showMore = document.createElement("div");
  5544. showMore.classList.add("show-more");
  5545. showMore.innerHTML = "显示更多/收起";
  5546. showMore.onclick = function(e2) {
  5547. e2.stopPropagation();
  5548. a.classList.toggle("show-all");
  5549. };
  5550. (_a = a.parentNode) == null ? void 0 : _a.append(showMore);
  5551. }
  5552. }
  5553. }
  5554. }
  5555. });
  5556. cbChecker({ type: "syncData" });
  5557. });
  5558. },
  5559. //解析A标签
  5560. parseA(a) {
  5561. let href = a.href;
  5562. let id;
  5563. if (href.includes("/t/")) {
  5564. id = a.pathname.substring("/t/".length);
  5565. }
  5566. return { href, id, title: a.innerText };
  5567. },
  5568. //创建记事本子条目
  5569. async createNoteItem(itemName) {
  5570. return;
  5571. },
  5572. //编辑记事本子条目
  5573. async editNoteItem(val, id) {
  5574. return;
  5575. },
  5576. //标签操作
  5577. async saveTags(val) {
  5578. return;
  5579. },
  5580. //已读楼层操作
  5581. async saveReadList(val) {
  5582. return;
  5583. },
  5584. //imgur图片删除hash操作
  5585. async saveImgurList(val) {
  5586. return;
  5587. },
  5588. //图片链接转Img标签
  5589. checkPhotoLink2Img(str) {
  5590. if (!str)
  5591. return;
  5592. try {
  5593. let imgWebs = [
  5594. /<a((?!<a).)*href="https?:\/\/((?!<a).)*imgur.com((?!<a).)*>(((?!<a).)*)<\/a>/g,
  5595. /<a((?!<a).)*href="https?:\/\/((?!<a).)*\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG) ((?!<a).)*>(((?!<a).)*)<\/a>/g
  5596. ];
  5597. imgWebs.map((v, i) => {
  5598. let has = str.matchAll(v);
  5599. let res2 = [...has];
  5600. res2.map((r2) => {
  5601. let p = i === 0 ? r2[4] : r2[5];
  5602. if (p) {
  5603. let link = p.toLowerCase();
  5604. let src = p;
  5605. if (link.includes(".png") || link.includes(".jpg") || link.includes(".jpeg") || link.includes(".gif")) {
  5606. } else {
  5607. src = p + ".png";
  5608. }
  5609. str = str.replace(r2[0], `<img src="${src}" data-originUrl="${p}" data-notice="此img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`);
  5610. }
  5611. });
  5612. });
  5613. } catch (e2) {
  5614. console.log("正则解析html里面的a标签的图片链接出错了");
  5615. }
  5616. return str;
  5617. },
  5618. //检测帖子回复长度
  5619. async checkPostReplies(id, needOpen = true) {
  5620. return new Promise(async (resolve) => {
  5621. var _a;
  5622. let showJsonUrl = `${location.origin}/api/topics/show.json?id=${id}`;
  5623. let r2 = await fetch(showJsonUrl);
  5624. if (r2) {
  5625. let res = await r2.json();
  5626. if (res) {
  5627. if (((_a = res[0]) == null ? void 0 : _a.replies) > MAX_REPLY_LIMIT) {
  5628. if (needOpen) {
  5629. functions.openNewTab(`https://www.v2ex.com/t/${id}?p=1&script=1`);
  5630. }
  5631. return resolve(true);
  5632. }
  5633. }
  5634. }
  5635. resolve(false);
  5636. });
  5637. }
  5638. };
  5639. window.vals = {
  5640. isMobile: !document.querySelector("#Rightbar")
  5641. };
  5642. window.functions = {};
  5643. async function sleep(time) {
  5644. return new Promise((resolve) => {
  5645. setTimeout(resolve, time);
  5646. });
  5647. }
  5648. async function cbChecker(val, count = 0) {
  5649. if (window.cb) {
  5650. window.cb(val);
  5651. } else {
  5652. while (!window.cb && count < 30) {
  5653. await sleep(500);
  5654. count++;
  5655. }
  5656. window.cb && window.cb(val);
  5657. }
  5658. }
  5659. function initMonkeyMenu() {
  5660. try {
  5661. _GM_registerMenuCommand("脚本设置", () => {
  5662. cbChecker({ type: "openSetting" });
  5663. });
  5664. _GM_registerMenuCommand("仓库地址", () => {
  5665. functions.openNewTab(DefaultVal.git);
  5666. });
  5667. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  5668. } catch (e2) {
  5669. console.error("无法使用Tampermonkey");
  5670. }
  5671. }
  5672. function initStyle() {
  5673. let style2 = `
  5674. html, body {
  5675. font-size: 62.5%;
  5676. }
  5677.  
  5678. :root{
  5679. --box-border-radius:8px;
  5680. }
  5681. .box{
  5682. box-shadow:rgba(0, 0, 0, 0.08) 0px 4px 12px;
  5683. }
  5684. #Tabs{
  5685. border-top-left-radius: var(--box-border-radius) !important;
  5686. border-top-right-radius: var(--box-border-radius) !important;
  5687. }
  5688. #Main .cell .count_livid {
  5689. font-size: 14px;
  5690. font-weight: 500;
  5691. padding: 3px 10px;
  5692. border-radius: 5px;
  5693. }
  5694.  
  5695. #Wrapper {
  5696. height: unset !important;
  5697. width: unset !important;
  5698. }
  5699.  
  5700. #Wrapper > .content {
  5701. height: unset !important;
  5702. width: unset !important;
  5703. max-width:1100px !important;
  5704. }
  5705.  
  5706. .post-item {
  5707. background: white;
  5708. }
  5709.  
  5710. .post-item > .post-content {
  5711. height: 0;
  5712. margin-top: 0;
  5713. }
  5714.  
  5715. .post-item:hover .toggle {
  5716. display: flex;
  5717. }
  5718.  
  5719. .toggle {
  5720. position: absolute;
  5721. right: ${window.config.viewType === "simple" ? "5rem" : 0};
  5722. top: 0.5rem;
  5723. width: 9rem;
  5724. height: 100%;
  5725. display: flex;
  5726. justify-content: flex-end;
  5727. align-items: flex-end;
  5728. cursor: pointer;
  5729. font-size: 1.2rem;
  5730. color: #ccc;
  5731. display: none;
  5732. }
  5733.  
  5734. .preview {
  5735. margin: 1rem 0;
  5736. border: 1px solid transparent;
  5737. border-radius: var(--box-border-radius);
  5738. cursor: pointer;
  5739. }
  5740.  
  5741. .preview:hover {
  5742. border: 1px solid #c8c8c8;
  5743. }
  5744.  
  5745. .preview > .post-content {
  5746. height: unset !important;
  5747. margin-top: 0.5rem !important;
  5748. }
  5749.  
  5750. .preview > .post-content.show-all {
  5751. max-height: unset;
  5752. -webkit-mask-image:none;
  5753. }
  5754.  
  5755. .preview .topic-link:link {
  5756. color: black !important;
  5757. }
  5758.  
  5759. .post-content {
  5760. margin-top: 0.5rem;
  5761. display: block;
  5762. max-height: 20rem;
  5763. overflow: hidden;
  5764. text-decoration: unset !important;
  5765. line-break: anywhere;
  5766. -webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);
  5767. }
  5768.  
  5769. .show-more {
  5770. display: none;
  5771. }
  5772.  
  5773. .preview > .show-more {
  5774. font-size: 1.3rem;
  5775. text-align: right;
  5776. height: 3rem;
  5777. display: flex;
  5778. align-items: center;
  5779. justify-content: center;
  5780. position: relative;
  5781. z-index: 9;
  5782. }
  5783.  
  5784. .post-content:visited {
  5785. color: #afb9c1 !important;
  5786. }
  5787.  
  5788. .post-content:link {
  5789. color: #494949;
  5790. }
  5791.  
  5792.  
  5793. .Night .post-item {
  5794. background: #18222d !important;
  5795. }
  5796.  
  5797. .Night .preview {
  5798. border: 1px solid #3b536e;
  5799. }
  5800.  
  5801. .Night .preview > .post-content:link {
  5802. color: #d1d5d9;
  5803. }
  5804.  
  5805. .Night .preview > .post-content:visited {
  5806. color: #393f4e !important;
  5807. }
  5808. .Night .preview .topic-link:link {
  5809. color: #c0dbff !important;
  5810. }
  5811. ${window.config.viewType === "simple" ? `
  5812. ${window.pageType !== PageType.Member ? `
  5813. .item table tr td:first-child{display:none;}
  5814. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  5815. .item table tr td .sep5{display:none;}
  5816. .item table tr td .topic_info{display:none;}
  5817. .item {border-bottom:none;}
  5818. .avatar,#avatar{display:none;}
  5819. ` : ""}
  5820. #Logo {background-image:url('https://i.imgur.com/i9VgUtM.png');}
  5821. .bigger a, .top:nth-last-child(5){color: transparent!important;text-shadow: #b0b0b0 0 0 6px;user-select: none;}
  5822. // .bigger a:before,.top:nth-last-child(5):before{content:'Mona Lisa';position: absolute;background: white;}
  5823. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  5824. ` : ""}
  5825.  
  5826. ${window.config.customBgColor ? `#Wrapper {
  5827. background-color: ${window.config.customBgColor} !important;
  5828. background-image: unset !important;
  5829. }` : ""}
  5830. .top{
  5831. position:relative;
  5832. }
  5833. .new:before{
  5834. content:'new';
  5835. position: absolute;
  5836. background: red;
  5837. font-size: 10px;
  5838. border-radius: 4px;
  5839. padding: 0px 2px;
  5840. color: white;
  5841. right: -9px;
  5842. top: -3px;
  5843. }
  5844. }
  5845.  
  5846. `;
  5847. let addStyle2 = document.createElement("style");
  5848. addStyle2.rel = "stylesheet";
  5849. addStyle2.type = "text/css";
  5850. addStyle2.innerHTML = style2;
  5851. window.document.head.append(addStyle2);
  5852. }
  5853. function qianDao() {
  5854. let timeNow = (/* @__PURE__ */ new Date()).getUTCFullYear() + "/" + ((/* @__PURE__ */ new Date()).getUTCMonth() + 1) + "/" + (/* @__PURE__ */ new Date()).getUTCDate();
  5855. if (window.pageType === PageType.Home) {
  5856. let qiandao = window.query('.box .inner a[href="/mission/daily"]');
  5857. if (qiandao) {
  5858. qianDao_(qiandao, timeNow);
  5859. } else if (window.win().doc.getElementById("gift_v2excellent")) {
  5860. window.win().doc.getElementById("gift_v2excellent").click();
  5861. localStorage.setItem("menu_clockInTime", timeNow);
  5862. console.info("[V2EX - 超级增强] 自动签到完成!");
  5863. } else {
  5864. console.info("[V2EX - 超级增强] 自动签到完成!");
  5865. }
  5866. } else {
  5867. let timeOld = localStorage.getItem("menu_clockInTime");
  5868. if (!timeOld || timeOld != timeNow) {
  5869. qianDaoStatus_(timeNow);
  5870. } else {
  5871. console.info("[V2EX - 超级增强] 自动签到完成!");
  5872. }
  5873. }
  5874. }
  5875. function qianDao_(qiandao, timeNow) {
  5876. let url = window.baseUrl + "/mission/daily/redeem?" + RegExp("once\\=(\\d+)").exec(document.querySelector("div#Top .tools, #menu-body").innerHTML)[0];
  5877. console.log("url", url);
  5878. $.get(url).then((r2) => {
  5879. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  5880. let html = $(bodyText[0]);
  5881. if (html.find("li.fa.fa-ok-sign").length) {
  5882. html = html.find("#Main").text().match(/已连续登录 (\d+?) 天/)[0];
  5883. localStorage.setItem("menu_clockInTime", timeNow);
  5884. console.info("[V2EX - 超级增强] 自动签到完成!");
  5885. if (qiandao) {
  5886. qiandao.textContent = `自动签到完成!${html}`;
  5887. qiandao.href = "javascript:void(0);";
  5888. }
  5889. } else {
  5890. _GM_notification({
  5891. text: "自动签到失败!请关闭其他插件或脚本。\n如果连续几天都签到失败,请联系作者解决!",
  5892. timeout: 4e3,
  5893. onclick() {
  5894. functions.feedback();
  5895. }
  5896. });
  5897. console.warn("[V2EX 增强] 自动签到失败!请关闭其他插件或脚本。如果连续几天都签到失败,请联系作者解决!");
  5898. if (qiandao)
  5899. qiandao.textContent = "自动签到失败!请尝试手动签到!";
  5900. }
  5901. });
  5902. }
  5903. function qianDaoStatus_(timeNow) {
  5904. $.get(window.baseUrl + "/mission/daily").then((r2) => {
  5905. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  5906. let html = $(bodyText[0]);
  5907. if (html.find('input[value^="领取"]').length) {
  5908. qianDao_(null, timeNow);
  5909. } else {
  5910. console.info("[V2EX 增强] 已经签过到了。");
  5911. localStorage.setItem("menu_clockInTime", timeNow);
  5912. }
  5913. });
  5914. }
  5915. function checkPageType() {
  5916. let l = window.location;
  5917. if (l.pathname === "/") {
  5918. window.pageType = PageType.Home;
  5919. } else if (l.href.match(/.com\/?tab=/)) {
  5920. window.pageType = PageType.Home;
  5921. } else if (l.href.match(/.com\/go\//)) {
  5922. if (!l.href.includes("/links")) {
  5923. window.pageType = PageType.Node;
  5924. }
  5925. } else if (l.href.match(/.com\/recent/)) {
  5926. window.pageType = PageType.Home;
  5927. } else if (l.href.match(/.com\/member/)) {
  5928. window.pageType = PageType.Member;
  5929. } else {
  5930. let r2 = l.href.match(/.com\/t\/([\d]+)/);
  5931. if (r2) {
  5932. window.pageType = PageType.Post;
  5933. window.pageData.id = r2[1];
  5934. if (l.search) {
  5935. let pr = l.href.match(/\?p=([\d]+)/);
  5936. if (pr)
  5937. window.pageData.pageNo = Number(pr[1]);
  5938. }
  5939. }
  5940. }
  5941. }
  5942. function initConfig() {
  5943. return new Promise((resolve) => {
  5944. let configStr = window.localStorage.getItem("v2ex-config");
  5945. if (configStr) {
  5946. let configObj = JSON.parse(configStr);
  5947. configObj = configObj[window.user.username ?? "default"];
  5948. if (configObj) {
  5949. window.config = Object.assign(window.config, configObj);
  5950. }
  5951. }
  5952. resolve(window.config);
  5953. });
  5954. }
  5955. function addSettingText() {
  5956. let setting = $(`<a href="javascript:void 0;" class="top ${window.config.version < window.currentVersion ? "new" : ""}">脚本设置</a>`);
  5957. setting.on("click", function() {
  5958. this.classList.remove("new");
  5959. cbChecker({ type: "openSetting" });
  5960. });
  5961. $(".tools").prepend(setting);
  5962. }
  5963. async function init() {
  5964. window.addEventListener("error", (e2) => {
  5965. let dom = e2.target;
  5966. let originImgUrl = dom.getAttribute("data-originurl");
  5967. if (originImgUrl) {
  5968. let a = document.createElement("a");
  5969. a.href = originImgUrl;
  5970. a.setAttribute("notice", "此标签由v2ex超级增强脚本转换图片失败后恢复");
  5971. a.innerText = originImgUrl;
  5972. dom.parentNode.replaceChild(a, dom);
  5973. }
  5974. }, true);
  5975. if (window.isNight) {
  5976. document.documentElement.classList.add("dark");
  5977. }
  5978. checkPageType();
  5979. initMonkeyMenu();
  5980. let top2 = document.querySelector(".tools .top:nth-child(2)");
  5981. if (top2 && top2.textContent !== "注册") {
  5982. window.user.username = top2.textContent;
  5983. window.user.avatar = $("#Rightbar .box .avatar").attr("src");
  5984. }
  5985. initConfig().then((r2) => {
  5986. addSettingText();
  5987. initStyle();
  5988. try {
  5989. if (window.config.autoSignin && window.user.username) {
  5990. qianDao();
  5991. }
  5992. } catch (e2) {
  5993. console.log("签到失败");
  5994. }
  5995. if (window.user.username)
  5996. ;
  5997. });
  5998. let box;
  5999. let list;
  6000. console.log(window.pageType);
  6001. switch (window.pageType) {
  6002. case PageType.Node:
  6003. box = window.win().doc.querySelectorAll("#Wrapper #Main .box");
  6004. let topics = box[1].querySelector("#TopicsNode");
  6005. list = topics.querySelectorAll(".cell");
  6006. list[0].before($section);
  6007. break;
  6008. case PageType.Home:
  6009. box = document.querySelector("#Wrapper #Main .box");
  6010. list = box.querySelectorAll(".item");
  6011. list[0].before($section);
  6012. break;
  6013. case PageType.Post:
  6014. box = document.querySelector("#Wrapper #Main .box");
  6015. box.after($section);
  6016. if (window.config.postWidth) {
  6017. let Main = $("#Main");
  6018. Main.css({
  6019. "width": window.config.postWidth,
  6020. margin: "unset"
  6021. });
  6022. $("#Wrapper > .content").css({
  6023. "max-width": "unset",
  6024. display: "flex",
  6025. "justify-content": "center",
  6026. gap: "20px"
  6027. });
  6028. Main.after($("#Rightbar"));
  6029. }
  6030. let post = window.clone(window.initPost);
  6031. post.id = window.pageData.id;
  6032. let body = $(window.document.body);
  6033. let htmlText = window.document.documentElement.outerHTML;
  6034. window.parse.parsePostContent(
  6035. post,
  6036. body,
  6037. htmlText
  6038. ).then(async (res) => {
  6039. await functions.cbChecker({ type: "postContent", value: res });
  6040. await window.parse.parseOp(res);
  6041. });
  6042. window.parse.getPostAllReplies(
  6043. post,
  6044. body,
  6045. htmlText,
  6046. window.pageData.pageNo
  6047. ).then(async (res1) => {
  6048. await functions.cbChecker({ type: "postReplies", value: res1 });
  6049. });
  6050. break;
  6051. case PageType.Member:
  6052. box = document.querySelector("#Wrapper #Main .box");
  6053. window.targetUserName = box[0].querySelector("h1").textContent;
  6054. if (window.config.openTag) {
  6055. box[0].style.borderBottom = "none";
  6056. box[0].style["border-bottom-left-radius"] = "0";
  6057. box[0].style["border-bottom-right-radius"] = "0";
  6058. }
  6059. list = box[1].querySelectorAll(".cell");
  6060. box[0].after($section);
  6061. break;
  6062. default:
  6063. window.stopMe = true;
  6064. cbChecker({ type: "syncData" });
  6065. console.error("未知页面");
  6066. break;
  6067. }
  6068. }
  6069. window.canParseV2exPage = !window.location.search.includes("script");
  6070. if (window.canParseV2exPage) {
  6071. init();
  6072. } else {
  6073. let box = document.querySelector("#Wrapper #Main .box");
  6074. box.after($section);
  6075. window.stopMe = true;
  6076. cbChecker({ type: "syncData" });
  6077. if (window.location.search.includes("script=0")) {
  6078. cbChecker({ type: "warningNotice", value: "脚本无法查看此主题,已为您单独打开此主题" });
  6079. }
  6080. if (window.location.search.includes("script=1")) {
  6081. cbChecker({ type: "warningNotice", value: "由于回复数量较多,已为您单独打开此主题并停止解析楼中楼" });
  6082. }
  6083. }
  6084. }
  6085. if (!isMobile) {
  6086. (o=>{if(typeof GM_addStyle=="function"){GM_addStyle(o);return}const r=document.createElement("style");r.textContent=o,document.head.append(r)})(' .tip[data-v-ee672411]{position:fixed;font-size:1.6rem;z-index:9999;max-width:10rem;border-radius:.5rem;padding:1rem;color:var(--color-font-8);background:var(--color-tooltip-bg);box-shadow:0 0 6px 1px var(--color-tooltip-shadow)}.v-enter-active[data-v-e7c0fbef],.v-leave-active[data-v-e7c0fbef]{transition:opacity .3s ease}.v-enter-from[data-v-e7c0fbef],.v-leave-to[data-v-e7c0fbef]{opacity:0}.username[data-v-e7c0fbef]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-e7c0fbef]{font-weight:700;color:var(--color-font-8)}.owner[data-v-e7c0fbef]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.mod[data-v-e7c0fbef]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.my-tag[data-v-e7c0fbef]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-e7c0fbef]{display:inline}.my-tag .remove[data-v-e7c0fbef]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-e7c0fbef]{font-size:2.4rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;position:absolute;display:none}.floor[data-v-e7c0fbef]{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-e7c0fbef]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-e7c0fbef]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-e7c0fbef],body[data-v-e7c0fbef]{font-size:62.5%}[data-v-e7c0fbef]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-e7c0fbef]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-e7c0fbef]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-e7c0fbef]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-e7c0fbef]{justify-content:flex-end}.flex-center[data-v-e7c0fbef]{justify-content:center}.p1[data-v-e7c0fbef]{padding:1rem}.p2[data-v-e7c0fbef]{padding:2rem}.p0[data-v-e7c0fbef]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-e7c0fbef]{text-underline-offset:.46ex;color:currentcolor;text-decoration:underline 1.5px}a[data-v-e7c0fbef]{text-decoration:none;cursor:pointer}a[data-v-e7c0fbef]:hover{text-decoration:underline}.tool[data-v-e7c0fbef]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg[data-v-e7c0fbef]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-e7c0fbef]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-e7c0fbef]{cursor:default}.tool.no-hover[data-v-e7c0fbef]:hover{background:unset!important}.tool.disabled[data-v-e7c0fbef]{cursor:not-allowed}.tool.disabled[data-v-e7c0fbef]:hover{background:unset!important}.my-node[data-v-e7c0fbef]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-e7c0fbef]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-e7c0fbef]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-e7c0fbef]{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-e7c0fbef]{color:var(--color-font);padding:.8rem 1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid var(--color-line)}.modal[data-v-e7c0fbef]{position:fixed;z-index:100;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-e7c0fbef]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-e7c0fbef]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-e7c0fbef]{position:relative}.modal .mask[data-v-e7c0fbef]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-e7c0fbef]{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid var(--color-radio-border);background:var(--box-background-alt-color)}.radio-group2 .radio[data-v-e7c0fbef]{cursor:pointer;background:transparent;padding:.5rem 1.2rem;border-left:1px solid var(--color-radio-border);font-size:1.3rem;color:var(--color-gray)}.radio-group2 .radio[data-v-e7c0fbef]:first-child{border-left:none}.radio-group2 .active[data-v-e7c0fbef]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-e7c0fbef]{position:relative;display:inline-flex;justify-content:center}input[data-v-e7c0fbef]{height:3rem;outline:unset;border:1px solid var(--color-input-border);padding:0 .5rem;border-radius:5px;box-sizing:border-box;transition:all .3s;background:var(--color-input-bg);color:var(--color-font)}input[data-v-e7c0fbef]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-e7c0fbef]:focus{border:1px solid var(--color-active)}.danger[data-v-e7c0fbef]{color:red!important}.switch[data-v-e7c0fbef]{width:4.5rem;height:2.2rem;border-radius:2rem;position:relative;display:flex;align-items:center;background:var(--color-swtich-bg);transition:all .3s}.switch.active[data-v-e7c0fbef]{background:var(--color-active)}.switch.active[data-v-e7c0fbef]:before{right:.2rem}.switch[data-v-e7c0fbef]:before{position:absolute;content:" ";transition:all .3s;right:calc(100% - 2rem);width:1.8rem;height:1.8rem;background:white;border-radius:50%}.setting-modal .modal-root[data-v-0c0fac4f]{z-index:9;background:var(--color-main-bg);border-radius:1.6rem;font-size:1.4rem;overflow:hidden;color:var(--color-font-pure)}.setting-modal .modal-root .modal-header[data-v-0c0fac4f]{padding:2.4rem;display:flex;justify-content:space-between}.setting-modal .modal-root .modal-header .title[data-v-0c0fac4f]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.setting-modal .modal-root .modal-header i[data-v-0c0fac4f]{cursor:pointer;font-size:2.2rem}.setting-modal .modal-root .body[data-v-0c0fac4f]{width:45vw;height:70vh;display:flex}.setting-modal .modal-root .body .left[data-v-0c0fac4f]{display:flex;flex-direction:column;justify-content:space-between;align-items:center;font-size:1.8rem}.setting-modal .modal-root .body .left .tabs[data-v-0c0fac4f]{padding:1rem 2rem;display:flex;flex-direction:column;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab[data-v-0c0fac4f]{cursor:pointer;padding:1rem 1.5rem;border-radius:.8rem;display:flex;align-items:center;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab.active[data-v-0c0fac4f]{background:var(--color-item-bg)}.setting-modal .modal-root .body .modal-content[data-v-0c0fac4f]{background:var(--color-second-bg);flex:1;height:100%;box-sizing:border-box;padding:1rem 1rem 1rem 2rem;border-radius:1.6rem;display:flex}.setting-modal .modal-root .body .modal-content .scroll[data-v-0c0fac4f]{flex:1;padding-right:1rem;overflow:auto}.setting-modal .modal-root .body .modal-content .scroll .row[data-v-0c0fac4f]{min-height:5rem;display:flex;justify-content:space-between;align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper[data-v-0c0fac4f]{height:3rem;flex:1;display:flex;justify-content:flex-end;align-items:center;gap:var(--space)}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper span[data-v-0c0fac4f]{text-align:right;font-size:1.4rem;color:gray}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key[data-v-0c0fac4f]{align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key input[data-v-0c0fac4f]{width:15rem;box-sizing:border-box;margin-right:1rem;height:2.8rem;outline:none;font-size:1.6rem;border:1px solid gray;border-radius:.3rem;padding:0 .5rem;background:var(--color-second-bg);color:var(--color-font-1)}.setting-modal .modal-root .body .modal-content .scroll .row .main-title[data-v-0c0fac4f]{font-size:2.2rem;font-weight:700;color:var(--color-font-8)}.setting-modal .modal-root .body .modal-content .scroll .row .item-title[data-v-0c0fac4f]{font-size:1.8rem}.setting-modal .modal-root .body .modal-content .scroll .desc[data-v-0c0fac4f]{margin-bottom:1rem;font-size:1.4rem;text-align:left;color:var(--color-font)}.setting-modal .modal-root .body .modal-content .scroll .project-desc[data-v-0c0fac4f]{text-align:start;font-size:1.6rem;padding-bottom:10rem}.setting-modal .modal-root .body .modal-content .scroll .line[data-v-0c0fac4f]{border-bottom:1px solid #c4c3c3}.loading[data-v-2697baa2]{border:2px solid;border-color:var(--color-loading-2) var(--color-loading-1) var(--color-loading-1) var(--color-loading-1);border-radius:100%;animation:circle-2697baa2 infinite 1s linear;width:2rem;height:2rem}.loading.small[data-v-2697baa2]{width:1.2rem;height:1.2rem}.loading.large[data-v-2697baa2]{width:3rem;height:3rem}@keyframes circle-2697baa2{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.base-button[data-v-5a7d79ba]{cursor:pointer;border-radius:.6rem;padding:0 1.5rem;display:inline-flex;align-items:center;justify-content:center;transition:all .3s;height:3.6rem;line-height:1;position:relative}.base-button .loading[data-v-5a7d79ba]{position:absolute}.base-button.disabled[data-v-5a7d79ba]{opacity:.6;cursor:not-allowed;-webkit-user-select:none;user-select:none}.base-button.small[data-v-5a7d79ba]{height:3rem}.base-button.small>span[data-v-5a7d79ba]{font-size:1.3rem}.base-button.large[data-v-5a7d79ba]{height:5rem;font-size:1.8rem;padding:0 2.2rem}.base-button.large>span[data-v-5a7d79ba]{font-size:1.8rem}.base-button[data-v-5a7d79ba]:hover:not(.link){opacity:.7}.base-button.primary[data-v-5a7d79ba]{background:var(--color-active)}.base-button.primary>span[data-v-5a7d79ba]{color:#fff}.base-button.gary[data-v-5a7d79ba]{background:#4b5563}.base-button.link[data-v-5a7d79ba]{border-radius:0;border-bottom:2px solid transparent}.base-button.link>span[data-v-5a7d79ba]{color:var(--color-font-8)}.base-button.link[data-v-5a7d79ba]:hover{border-bottom:2px solid var(--color-font-8)}.base-button.active[data-v-5a7d79ba]{opacity:.4}.key-notice[data-v-5a7d79ba]{margin-left:1rem;display:flex;align-items:center;justify-content:center;font-size:1.2rem;color:#fff}.key-notice .key[data-v-5a7d79ba]{transform:scale(.8)}.pop-confirm-content[data-v-05424197]{position:fixed;background:var(--color-tooltip-bg);box-shadow:0 0 6px 1px var(--color-tooltip-shadow);color:var(--color-font-8);padding:1.5rem;border-radius:.8rem;transform:translate(-50%,calc(-100% - 1rem));z-index:999}.pop-confirm-content .text[data-v-05424197]{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-05424197]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}.Author[data-v-c450f45f]{display:flex;align-items:center;justify-content:space-between;font-size:1.2rem;position:relative}.Author.expand[data-v-c450f45f]{margin-bottom:0}.Author .Author-left[data-v-c450f45f]{display:flex;align-items:center;max-width:65%;word-break:break-all}.Author .Author-left .username[data-v-c450f45f]{font-size:1.4rem;margin-right:1rem}.Author .Author-left .expand-icon[data-v-c450f45f]{cursor:pointer;margin-right:.8rem;width:2rem;height:2rem;transform:rotate(90deg)}.Author .Author-left .avatar[data-v-c450f45f]{margin-right:1rem;display:flex}.Author .Author-left .avatar img[data-v-c450f45f]{width:2.8rem;height:2.8rem;border-radius:.4rem}.Author .Author-left .texts[data-v-c450f45f]{flex:1}.Author .Author-left .owner[data-v-c450f45f]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.Author .Author-left .dup[data-v-c450f45f]{display:inline-block;background-color:transparent;color:red;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid red;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.Author .Author-left .mod[data-v-c450f45f]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.Author:hover .add-tag[data-v-c450f45f]{display:inline-block}.Author .Author-right[data-v-c450f45f]{position:absolute;right:0;display:flex;align-items:center}.Author .Author-right .toolbar[data-v-c450f45f]{display:flex;align-items:center;color:var(--color-gray);opacity:0;font-weight:700;gap:1rem}.Author .Author-right .toolbar[data-v-c450f45f]:hover{opacity:1}.post-editor-wrapper[data-v-fb753464]{width:100%;box-sizing:border-box;position:relative;overflow:hidden;transition:all .3s;color:var(--color-font)}.post-editor-wrapper.reply-post .post-editor[data-v-fb753464]{border:1px solid var(--color-line)}.post-editor-wrapper.reply-post.isFocus .post-editor[data-v-fb753464]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment[data-v-fb753464]{border-radius:var(--box-border-radius);overflow:hidden;border:1px solid var(--color-line)}.post-editor-wrapper.reply-comment.isFocus[data-v-fb753464]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment .toolbar[data-v-fb753464]{background:var(--color-editor-toolbar)}.post-editor-wrapper .post-editor[data-v-fb753464]{border-radius:var(--box-border-radius);transition:border .3s;width:100%;max-width:100%;padding:.6rem 1.4rem;box-sizing:border-box;outline:none;font-family:Avenir,Helvetica,Arial,sans-serif;font-size:1.4rem;min-height:13rem;resize:none;background:var(--box-background-color);color:var(--color-font-pure);border:1px solid transparent}.post-editor-wrapper .toolbar[data-v-fb753464]{box-sizing:border-box;padding:.5rem 1rem;width:100%;position:relative;display:flex;justify-content:space-between;align-items:center}.post-editor-wrapper .toolbar .left[data-v-fb753464]{display:flex;gap:1rem}.post-editor-wrapper .toolbar .left svg[data-v-fb753464]{cursor:pointer}.post-editor-wrapper .toolbar .left .upload input[data-v-fb753464]{cursor:pointer;position:absolute;width:20px;height:20px;opacity:0}.post-editor-wrapper .toolbar span[data-v-fb753464]{color:gray;font-size:1.3rem}.post-editor-wrapper .get-cursor[data-v-fb753464]{border-radius:var(--box-border-radius);transition:border .3s;width:100%;max-width:100%;padding:.6rem 1.4rem;box-sizing:border-box;outline:none;font-family:Avenir,Helvetica,Arial,sans-serif;font-size:1.4rem;min-height:13rem;resize:none;background:var(--box-background-color);color:var(--color-font-pure);border:1px solid transparent;position:absolute;top:0;z-index:-100}.post-editor-wrapper .emoticon-pack[data-v-fb753464]{z-index:999999999;border-radius:1rem;padding:1rem;width:31rem;max-width:31rem;height:30rem;max-height:30rem;overflow:auto;background:var(--color-third-bg);border:1px solid var(--color-font-3);box-shadow:0 9px 24px -3px #0000000f,0 4px 8px -1px #0000001f;position:fixed;bottom:11rem;left:14rem}.post-editor-wrapper .emoticon-pack i[data-v-fb753464]{cursor:pointer;position:absolute;right:2rem;font-size:2rem;color:#e2e2e2}.post-editor-wrapper .emoticon-pack .list[data-v-fb753464]{margin:1rem 0}.post-editor-wrapper .emoticon-pack img[data-v-fb753464]{cursor:pointer;width:3rem;height:3rem;padding:.5rem}.post-editor-wrapper .emoticon-pack span[data-v-fb753464]{display:inline-block;cursor:pointer;font-size:2.3rem;padding:.5rem}.v-enter-active[data-v-2c9a538c],.v-leave-active[data-v-2c9a538c]{transition:opacity .3s ease}.v-enter-from[data-v-2c9a538c],.v-leave-to[data-v-2c9a538c]{opacity:0}.username[data-v-2c9a538c]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-2c9a538c]{font-weight:700;color:var(--color-font-8)}.owner[data-v-2c9a538c]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.mod[data-v-2c9a538c]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.my-tag[data-v-2c9a538c]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-2c9a538c]{display:inline}.my-tag .remove[data-v-2c9a538c]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-2c9a538c]{font-size:2.4rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;position:absolute;display:none}.floor[data-v-2c9a538c]{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-2c9a538c]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-2c9a538c]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-2c9a538c],body[data-v-2c9a538c]{font-size:62.5%}[data-v-2c9a538c]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-2c9a538c]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-2c9a538c]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-2c9a538c]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-2c9a538c]{justify-content:flex-end}.flex-center[data-v-2c9a538c]{justify-content:center}.p1[data-v-2c9a538c]{padding:1rem}.p2[data-v-2c9a538c]{padding:2rem}.p0[data-v-2c9a538c]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-2c9a538c]{text-underline-offset:.46ex;color:currentcolor;text-decoration:underline 1.5px}a[data-v-2c9a538c]{text-decoration:none;cursor:pointer}a[data-v-2c9a538c]:hover{text-decoration:underline}.tool[data-v-2c9a538c]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg[data-v-2c9a538c]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-2c9a538c]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-2c9a538c]{cursor:default}.tool.no-hover[data-v-2c9a538c]:hover{background:unset!important}.tool.disabled[data-v-2c9a538c]{cursor:not-allowed}.tool.disabled[data-v-2c9a538c]:hover{background:unset!important}.my-node[data-v-2c9a538c]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-2c9a538c]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-2c9a538c]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-2c9a538c]{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-2c9a538c]{color:var(--color-font);padding:.8rem 1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid var(--color-line)}.modal[data-v-2c9a538c]{position:fixed;z-index:100;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-2c9a538c]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-2c9a538c]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-2c9a538c]{position:relative}.modal .mask[data-v-2c9a538c]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-2c9a538c]{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid var(--color-radio-border);background:var(--box-background-alt-color)}.radio-group2 .radio[data-v-2c9a538c]{cursor:pointer;background:transparent;padding:.5rem 1.2rem;border-left:1px solid var(--color-radio-border);font-size:1.3rem;color:var(--color-gray)}.radio-group2 .radio[data-v-2c9a538c]:first-child{border-left:none}.radio-group2 .active[data-v-2c9a538c]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-2c9a538c]{position:relative;display:inline-flex;justify-content:center}input[data-v-2c9a538c]{height:3rem;outline:unset;border:1px solid var(--color-input-border);padding:0 .5rem;border-radius:5px;box-sizing:border-box;transition:all .3s;background:var(--color-input-bg);color:var(--color-font)}input[data-v-2c9a538c]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-2c9a538c]:focus{border:1px solid var(--color-active)}.danger[data-v-2c9a538c]{color:red!important}.html-wrapper[data-v-2c9a538c]{position:relative}.html-wrapper .mask[data-v-2c9a538c]{max-height:90rem;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 80%,transparent)}.html-wrapper .expand[data-v-2c9a538c]{position:absolute;z-index:1;bottom:2rem;padding:.2rem 1.5rem;border-radius:2rem;border:1px solid gray;background:white;color:gray;left:50%;transform:translate(-50%);cursor:pointer}.comment[data-v-888958af]{width:100%;box-sizing:border-box;margin-top:.6rem}.comment.isLevelOne[data-v-888958af]{border-bottom:1px solid var(--color-line);padding:.8rem 1rem;margin-top:0}.comment.ding[data-v-888958af]{background:rgba(255,255,0,.3)!important}.comment.isSimple .avatar[data-v-888958af],.comment.isSimple .expand-line[data-v-888958af]{display:none}.comment.isSimple .simple-wrapper[data-v-888958af]{padding-left:2.8rem}.comment.isSimple .w[data-v-888958af]{padding-left:0!important;padding-top:.5rem}.comment .comment-content-w .more[data-v-888958af]{text-align:center;margin:2rem 0}.comment .comment-content[data-v-888958af]{display:flex;position:relative}.comment .comment-content .expand-line[data-v-888958af]{cursor:pointer;margin-top:.6rem;width:2.8rem;min-width:2.8rem;position:relative}.comment .comment-content .expand-line[data-v-888958af]:after{position:absolute;left:50%;content:" ";height:100%;width:0;border-right:1px solid var(--color-line)}.comment .comment-content .expand-line[data-v-888958af]:hover:after{border-right:2px solid var(--color-active)}.comment .comment-content .right[data-v-888958af]{flex:1;width:calc(100% - 3rem)}.comment .comment-content .right .w[data-v-888958af]{padding-left:1rem}.comment .comment-content .right .w .post-editor-wrapper[data-v-888958af]{margin-top:1rem}.wrong-wrapper[data-v-888958af]{font-size:1.4rem;margin-bottom:1rem}.wrong-wrapper span[data-v-888958af]{cursor:pointer}.wrong-wrapper .del-line[data-v-888958af]{text-decoration:line-through}.wrong-wrapper .wrong-icon[data-v-888958af]{margin-left:.5rem}.wrong-wrapper .warning[data-v-888958af]{border-top:1px solid #e1e1e1;border-bottom:1px solid #e1e1e1;padding:1rem 0;margin-top:1rem;font-size:1.2rem;color:red}.toolbar[data-v-c98b8c46]{border-top:1px solid var(--color-line);height:3.8rem;padding-left:.6rem;display:flex;align-items:center;color:var(--color-gray);font-size:1.2rem;font-weight:700;gap:1rem}.comment[data-v-953d8ab1]{width:100%;box-sizing:border-box;display:flex;gap:1rem;padding:1rem;border-bottom:1px solid var(--color-line)}.comment.isSimple .avatar[data-v-953d8ab1]{display:none}.comment.isSimple .reply_content[data-v-953d8ab1]{margin-top:.5rem!important}.comment .avatar[data-v-953d8ab1]{display:flex}.comment .avatar img[data-v-953d8ab1]{width:3.8rem;height:3.8rem;border-radius:.3rem}.comment .comment-body[data-v-953d8ab1]{flex:1;display:flex;flex-direction:column}.comment .comment-body .texts[data-v-953d8ab1]{display:flex;align-items:center}.comment .comment-body .reply_content[data-v-953d8ab1]{margin-top:1rem;max-width:calc(100% - 5rem)}.comment .isRight[data-v-953d8ab1]{align-items:flex-end}.comment .isRight .owner[data-v-953d8ab1],.comment .isRight .mod[data-v-953d8ab1],.comment .isRight .username[data-v-953d8ab1]{margin:0 0 0 1rem}.comment .Author-right[data-v-953d8ab1]{display:flex;flex-direction:column;align-items:center}.comment .Author-right .floor[data-v-953d8ab1]{margin-left:0}.comment .Author-right .jump[data-v-953d8ab1]{color:#929596;margin-top:.4rem;font-size:1.4rem}.comment .point[data-v-953d8ab1]{margin:0 .5rem;font-size:1.4rem;display:flex;gap:.5rem;align-items:center;font-weight:700;color:#000}.sticky{position:sticky;bottom:-2px;z-index:2;background:var(--box-background-hover-color)!important}.sticky[stuck]{box-shadow:0 2px 20px #00000059!important}.v-enter-active[data-v-7f8ab1e3],.v-leave-active[data-v-7f8ab1e3]{transition:opacity .3s ease}.v-enter-from[data-v-7f8ab1e3],.v-leave-to[data-v-7f8ab1e3]{opacity:0}.username[data-v-7f8ab1e3]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-7f8ab1e3]{font-weight:700;color:var(--color-font-8)}.owner[data-v-7f8ab1e3]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.mod[data-v-7f8ab1e3]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.my-tag[data-v-7f8ab1e3]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-7f8ab1e3]{display:inline}.my-tag .remove[data-v-7f8ab1e3]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-7f8ab1e3]{font-size:2.4rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;position:absolute;display:none}.floor[data-v-7f8ab1e3]{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-7f8ab1e3]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-7f8ab1e3]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-7f8ab1e3],body[data-v-7f8ab1e3]{font-size:62.5%}[data-v-7f8ab1e3]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-7f8ab1e3]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-7f8ab1e3]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-7f8ab1e3]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-7f8ab1e3]{justify-content:flex-end}.flex-center[data-v-7f8ab1e3]{justify-content:center}.p1[data-v-7f8ab1e3]{padding:1rem}.p2[data-v-7f8ab1e3]{padding:2rem}.p0[data-v-7f8ab1e3]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-7f8ab1e3]{text-underline-offset:.46ex;color:currentcolor;text-decoration:underline 1.5px}a[data-v-7f8ab1e3]{text-decoration:none;cursor:pointer}a[data-v-7f8ab1e3]:hover{text-decoration:underline}.tool[data-v-7f8ab1e3]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg[data-v-7f8ab1e3]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-7f8ab1e3]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-7f8ab1e3]{cursor:default}.tool.no-hover[data-v-7f8ab1e3]:hover{background:unset!important}.tool.disabled[data-v-7f8ab1e3]{cursor:not-allowed}.tool.disabled[data-v-7f8ab1e3]:hover{background:unset!important}.my-node[data-v-7f8ab1e3]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-7f8ab1e3]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-7f8ab1e3]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-7f8ab1e3]{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-7f8ab1e3]{color:var(--color-font);padding:.8rem 1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid var(--color-line)}.modal[data-v-7f8ab1e3]{position:fixed;z-index:100;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-7f8ab1e3]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-7f8ab1e3]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-7f8ab1e3]{position:relative}.modal .mask[data-v-7f8ab1e3]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-7f8ab1e3]{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid var(--color-radio-border);background:var(--box-background-alt-color)}.radio-group2 .radio[data-v-7f8ab1e3]{cursor:pointer;background:transparent;padding:.5rem 1.2rem;border-left:1px solid var(--color-radio-border);font-size:1.3rem;color:var(--color-gray)}.radio-group2 .radio[data-v-7f8ab1e3]:first-child{border-left:none}.radio-group2 .active[data-v-7f8ab1e3]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-7f8ab1e3]{position:relative;display:inline-flex;justify-content:center}input[data-v-7f8ab1e3]{height:3rem;outline:unset;border:1px solid var(--color-input-border);padding:0 .5rem;border-radius:5px;box-sizing:border-box;transition:all .3s;background:var(--color-input-bg);color:var(--color-font)}input[data-v-7f8ab1e3]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-7f8ab1e3]:focus{border:1px solid var(--color-active)}.danger[data-v-7f8ab1e3]{color:red!important}.Post[data-v-7f8ab1e3]{position:unset!important;background:transparent!important;overflow:unset!important}.Post .main[data-v-7f8ab1e3]{background:transparent!important;padding:unset!important;width:100%!important}.Post .close-btn[data-v-7f8ab1e3]{display:none}.post-detail[data-v-7f8ab1e3]{text-align:start;position:fixed;z-index:99;left:0;right:0;bottom:0;top:0;background:rgba(46,47,48,.8);overflow:auto;font-size:1.4rem;display:flex;justify-content:center;flex-wrap:wrap}.post-detail[data-v-7f8ab1e3] .subtle{background-color:#ecfdf5e6;border-left:4px solid #a7f3d0}.post-detail.isNight[data-v-7f8ab1e3] .subtle{background-color:#1a3332;border-left:4px solid #047857}.post-detail .main[data-v-7f8ab1e3]{display:flex;justify-content:flex-end;padding:3rem 8rem 15rem;background:var(--color-main-bg);position:relative;outline:none}.post-detail .main .main-wrapper[data-v-7f8ab1e3]{width:77rem;padding-bottom:2rem;display:flex;flex-direction:column;align-items:center;position:relative}.post-detail .main .main-wrapper .post-wrapper .header:hover .add-tag[data-v-7f8ab1e3]{display:inline-block}.post-detail .main .main-wrapper .loading-wrapper[data-v-7f8ab1e3]{height:20rem;display:flex;justify-content:center;align-items:center}.post-detail .main .main-wrapper #no-comments-yet[data-v-7f8ab1e3]{color:#a9a9a9;font-weight:700;text-align:center;width:100%;margin-bottom:2rem;box-sizing:border-box}.post-detail .main .relationReply[data-v-7f8ab1e3]{position:fixed;width:25vw;top:6.5rem;bottom:15rem;z-index:100;transform:translate(calc(100% + 2rem));font-size:2rem;overflow:hidden}.post-detail .main .relationReply .my-cell[data-v-7f8ab1e3]{background:var(--color-second-bg);border-radius:var(--box-border-radius) var(--box-border-radius) 0 0}.post-detail .main .relationReply .comments[data-v-7f8ab1e3]{max-height:calc(100% - 4.2rem);overflow:auto;background:var(--color-second-bg);border-radius:0 0 var(--box-border-radius) var(--box-border-radius)}.post-detail .main .call-list[data-v-7f8ab1e3]{z-index:9;position:absolute;top:12rem;border:1px solid var(--color-main-bg);background:var(--color-call-list-bg);box-shadow:0 5px 15px #0000001a;overflow:auto;max-height:30rem;border-radius:var(--box-border-radius);min-width:8rem;box-sizing:content-box}.post-detail .main .call-list .call-item[data-v-7f8ab1e3]{border-top:1px solid var(--color-main-bg);height:3rem;display:flex;padding:0 1rem;align-items:center;cursor:pointer;font-size:14px;box-sizing:border-box}.post-detail .main .call-list .call-item .select[data-v-7f8ab1e3],.post-detail .main .call-list .call-item[data-v-7f8ab1e3]:hover,.post-detail .main .call-list .call-item.select[data-v-7f8ab1e3]{background:var(--color-main-bg);text-decoration:none}.post-detail .main .call-list .call-item[data-v-7f8ab1e3]:nth-child(1){border-top:1px solid transparent}@media screen and (max-width: 1500px){.post-detail .main-wrapper[data-v-7f8ab1e3]{width:65vw!important}}@media screen and (max-width: 1280px){.post-detail .main-wrapper[data-v-7f8ab1e3]{width:75vw!important}}@media screen and (max-width: 960px){.post-detail .main-wrapper[data-v-7f8ab1e3]{width:100vw!important}}.post-detail .scroll-top[data-v-7f8ab1e3]{cursor:pointer;position:fixed;border-radius:.6rem;display:flex;align-items:center;justify-content:center;bottom:10rem;z-index:99;padding:.8rem 0;gap:1rem;width:4.5rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg)}.post-detail .refresh[data-v-7f8ab1e3]{cursor:pointer;position:fixed;border-radius:.6rem;display:flex;align-items:center;justify-content:center;bottom:10rem;z-index:99;padding:.8rem 0;gap:1rem;width:4.5rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);bottom:23.5rem}.post-detail .scroll-to[data-v-7f8ab1e3]{cursor:pointer;position:fixed;border-radius:.6rem;align-items:center;justify-content:center;bottom:10rem;z-index:99;padding:.8rem 0;gap:1rem;width:4.5rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);bottom:15rem;display:flex;flex-direction:column}.post-detail .scroll-to input[data-v-7f8ab1e3]{height:2.6rem;width:3.6rem;font-size:1.4rem;text-align:center;color:gray}.post-detail .read-notice[data-v-7f8ab1e3]{display:flex;align-items:center;color:gray}.post-detail .read-notice .jump[data-v-7f8ab1e3]{background:var(--color-third-bg);color:gray;padding:.3rem 1rem;border-radius:.4rem;margin:0 1rem;cursor:pointer}.post-detail .close-btn[data-v-7f8ab1e3]{color:#b6b6b6;cursor:pointer;position:fixed;top:3rem;transform:translate(4rem);font-size:2rem}.post-detail .top-reply[data-v-7f8ab1e3]{color:var(--color-font-3);cursor:pointer;font-size:2rem;display:flex}.post-detail .top-reply i[data-v-7f8ab1e3]{padding:0 1rem}.base64_tooltip[data-v-618144eb]{box-shadow:0 3px 6px -4px #0000001f,0 6px 16px #00000014,0 9px 28px 8px #0000000d;background:var(--color-third-bg);min-height:2.2rem;max-width:20rem;padding:1rem;position:fixed;z-index:9998;display:flex;align-items:center;border-radius:.5rem;cursor:pointer;line-break:anywhere;font-size:1.4rem;color:var(--color-font-8)}.base64_tooltip svg[data-v-618144eb]{margin-left:1rem;min-width:1.8rem}.base64_tooltip[data-v-618144eb] .base-button{margin-left:1rem;margin-top:1rem}.msg[data-v-defce7f2]{cursor:default;margin-bottom:2rem;display:flex;font-size:1.4rem;box-sizing:border-box;border-radius:var(--box-border-radius);color:var(--color-font-8);background:var(--color-tooltip-bg);box-shadow:0 0 6px 1px var(--color-tooltip-shadow)}.msg.success .left[data-v-defce7f2]{background:var(--color-active)}.msg.warning .left[data-v-defce7f2]{background:#c8c002}.msg.error .left[data-v-defce7f2]{background:red}.msg .left[data-v-defce7f2]{border-radius:var(--box-border-radius) 0 0 var(--box-border-radius);display:flex;align-items:center;background:var(--color-active)}.msg .left svg[data-v-defce7f2]{margin:0 .3rem;cursor:pointer}.msg .right[data-v-defce7f2]{flex:1;padding:1rem 2rem;display:flex;justify-content:space-between;align-items:center}.tag-modal .wrapper[data-v-674b86aa]{z-index:9;background:var(--color-main-bg);color:var(--color-font-8);border-radius:1.6rem;font-size:1.4rem;padding:2rem 4rem;width:25rem}.tag-modal .wrapper .title[data-v-674b86aa]{font-weight:700}.tag-modal .wrapper .btns[data-v-674b86aa]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1.5rem;font-size:1.4rem}.msgs[data-v-b73f4332]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.tag-modal .modal-root[data-v-882b932b]{z-index:9;background:var(--color-second-bg);color:var(--color-font-8);border-radius:1.6rem;font-size:1.4rem;width:50vw;height:70vh;display:flex;flex-direction:column}.tag-modal .modal-root .modal-header[data-v-882b932b]{padding:2.4rem;display:flex;justify-content:space-between}.tag-modal .modal-root .modal-header .title[data-v-882b932b]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.tag-modal .modal-root .modal-header i[data-v-882b932b]{cursor:pointer;font-size:2.2rem}.tag-modal .modal-root .modal-body[data-v-882b932b]{padding:2rem;padding-top:0;flex:1;overflow:auto}.tag-modal .modal-root .modal-body[data-v-882b932b] .cell{padding:2rem}.v-enter-active,.v-leave-active{transition:opacity .3s ease}.v-enter-from,.v-leave-to{opacity:0}.username{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num{font-weight:700;color:var(--color-font-8)}.owner{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.mod{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.my-tag{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove{display:inline}.my-tag .remove{cursor:pointer;margin-left:.5rem;display:none}.add-tag{font-size:2.4rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;position:absolute;display:none}.floor{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html,body{font-size:62.5%}::-webkit-scrollbar{width:1rem;height:1rem}::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex{display:flex;align-items:center;justify-content:space-between}.flex-end{justify-content:flex-end}.flex-center{justify-content:center}.p1{padding:1rem}.p2{padding:2rem}.p0{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http]{text-underline-offset:.46ex;color:currentcolor;text-decoration:underline 1.5px}a{text-decoration:none;cursor:pointer}a:hover{text-decoration:underline}.tool{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg{width:1.6rem!important;height:1.6rem!important}.tool:hover{background:var(--color-third-bg)}.tool.no-hover{cursor:default}.tool.no-hover:hover{background:unset!important}.tool.disabled{cursor:not-allowed}.tool.disabled:hover{background:unset!important}.my-node{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node:hover{text-decoration:none;background:#e2e2e2}.msgs{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box;transition:background-color .3s}.my-cell{color:var(--color-font);padding:.8rem 1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid var(--color-line)}.modal{position:fixed;z-index:100;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option{display:flex;align-items:center;padding:.6rem 0}.modal .option>span{position:relative}.modal .mask{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid var(--color-radio-border);background:var(--box-background-alt-color)}.radio-group2 .radio{cursor:pointer;background:transparent;padding:.5rem 1.2rem;border-left:1px solid var(--color-radio-border);font-size:1.3rem;color:var(--color-gray)}.radio-group2 .radio:first-child{border-left:none}.radio-group2 .active{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm{position:relative;display:inline-flex;justify-content:center}input{height:3rem;outline:unset;border:1px solid var(--color-input-border);padding:0 .5rem;border-radius:5px;box-sizing:border-box;transition:all .3s;background:var(--color-input-bg);color:var(--color-font)}input:hover{border:1px solid var(--color-input-border-hover)}input:focus{border:1px solid var(--color-active)}.danger{color:red!important}.target-user-tags[data-v-6c0e87a5]{background:var(--color-second-bg);color:var(--color-font);word-break:break-all;text-align:start;font-size:1.4rem;box-shadow:0 2px 3px #0000001a;border-bottom-left-radius:3px;border-bottom-right-radius:3px}.target-user-tags .add-tag[data-v-6c0e87a5]{display:inline-block}.loaded[data-v-6c0e87a5]{font-size:1.4rem;display:flex;align-items:center;gap:1rem} ');
  6087.  
  6088. console.log("V2EX PC端");
  6089. run();
  6090. let vueApp = vue.createApp(App);
  6091. vueApp.config.unwrapInjectedRef = true;
  6092. vueApp.mount($section);
  6093. }
  6094.  
  6095. })(Vue);