V2EX Next V2Next

V2Next - 一个好用的V2EX脚本!手机 App 已发布

  1. // ==UserScript==
  2. // @name V2EX Next V2Next
  3. // @namespace http://tampermonkey.net/
  4. // @version 10.30
  5. // @author zyronon
  6. // @description V2Next - 一个好用的V2EX脚本!手机 App 已发布
  7. // @license GPL License
  8. // @icon https://vtonext.vercel.app/favicon.ico
  9. // @homepage https://github.com/zyronon/V2Next
  10. // @homepageURL https://github.com/zyronon/V2Next
  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/changes*
  19. // @match https://*.v2ex.com/
  20. // @match https://*.v2ex.com/?tab=*
  21. // @match https://*.v2ex.com/t/*
  22. // @match https://*.v2ex.com/recent*
  23. // @match https://*.v2ex.com/go/*
  24. // @match https://*.v2ex.com/member/*
  25. // @match https://*.v2ex.com/changes*
  26. // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js
  27. // @require https://cdn.jsdelivr.net/npm/vue@3.4.14/dist/vue.global.prod.min.js
  28. // @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js
  29. // @grant GM_addStyle
  30. // @grant GM_openInTab
  31. // @grant GM_registerMenuCommand
  32. // ==/UserScript==
  33.  
  34.  
  35. (function (vue, dayjs) {
  36. 'use strict';
  37.  
  38. var PageType = /* @__PURE__ */ ((PageType2) => {
  39. PageType2["Home"] = "Home";
  40. PageType2["Node"] = "Node";
  41. PageType2["Post"] = "Post";
  42. PageType2["Member"] = "Member";
  43. PageType2["Changes"] = "Changes";
  44. PageType2["Hot"] = "Hot";
  45. return PageType2;
  46. })(PageType || {});
  47. var CommentDisplayType = /* @__PURE__ */ ((CommentDisplayType2) => {
  48. CommentDisplayType2[CommentDisplayType2["FloorInFloor"] = 0] = "FloorInFloor";
  49. CommentDisplayType2[CommentDisplayType2["FloorInFloorNoCallUser"] = 4] = "FloorInFloorNoCallUser";
  50. CommentDisplayType2[CommentDisplayType2["FloorInFloorNested"] = 5] = "FloorInFloorNested";
  51. CommentDisplayType2[CommentDisplayType2["Like"] = 1] = "Like";
  52. CommentDisplayType2[CommentDisplayType2["V2exOrigin"] = 2] = "V2exOrigin";
  53. CommentDisplayType2[CommentDisplayType2["OnlyOp"] = 3] = "OnlyOp";
  54. CommentDisplayType2[CommentDisplayType2["New"] = 6] = "New";
  55. return CommentDisplayType2;
  56. })(CommentDisplayType || {});
  57. const _sfc_main$m = {
  58. name: "Tooltip",
  59. props: {
  60. title: {
  61. type: String,
  62. default() {
  63. return "";
  64. }
  65. },
  66. disabled: {
  67. type: Boolean,
  68. default() {
  69. return false;
  70. }
  71. }
  72. },
  73. data() {
  74. return {
  75. show: false
  76. };
  77. },
  78. methods: {
  79. showPop(e2) {
  80. if (this.disabled)
  81. return;
  82. if (!this.title)
  83. return;
  84. e2.stopPropagation();
  85. let rect = e2.target.getBoundingClientRect();
  86. this.show = true;
  87. vue.nextTick(() => {
  88. var _a, _b;
  89. let tip = (_b = (_a = this.$refs) == null ? void 0 : _a.tip) == null ? void 0 : _b.getBoundingClientRect();
  90. if (!tip)
  91. return;
  92. if (rect.top < 50) {
  93. this.$refs.tip.style.top = rect.top + rect.height + 10 + "px";
  94. } else {
  95. this.$refs.tip.style.top = rect.top - tip.height - 10 + "px";
  96. }
  97. let tipWidth = tip.width;
  98. let rectWidth = rect.width;
  99. this.$refs.tip.style.left = rect.left - (tipWidth - rectWidth) / 2 + "px";
  100. });
  101. }
  102. },
  103. render() {
  104. let Vnode = this.$slots.default()[0];
  105. return vue.createVNode(vue.Fragment, null, [this.show && this.title && vue.createVNode(vue.Teleport, {
  106. "to": "body"
  107. }, {
  108. default: () => [vue.createVNode(vue.Transition, {
  109. "name": "fade"
  110. }, {
  111. default: () => [vue.createVNode("div", {
  112. "ref": "tip",
  113. "className": "tip"
  114. }, [this.title])]
  115. })]
  116. }), vue.createVNode(Vnode, {
  117. "onClick": () => this.show = false,
  118. "onmouseenter": (e2) => this.showPop(e2),
  119. "onmouseleave": () => this.show = false
  120. }, null)]);
  121. }
  122. };
  123. const _export_sfc = (sfc, props) => {
  124. const target = sfc.__vccOpts || sfc;
  125. for (const [key, val] of props) {
  126. target[key] = val;
  127. }
  128. return target;
  129. };
  130. const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$m, [["__scopeId", "data-v-ee672411"]]);
  131. const _sfc_main$l = /* @__PURE__ */ vue.defineComponent({
  132. __name: "BaseSwitch",
  133. props: {
  134. modelValue: { type: Boolean }
  135. },
  136. emits: ["update:modelValue"],
  137. setup(__props, { emit: __emit }) {
  138. return (_ctx, _cache) => {
  139. return vue.openBlock(), vue.createElementBlock("div", {
  140. class: vue.normalizeClass(["switch", { active: _ctx.modelValue }]),
  141. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", !_ctx.modelValue))
  142. }, null, 2);
  143. };
  144. }
  145. });
  146. const BaseSwitch = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-e7c0fbef"]]);
  147. var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)();
  148. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  149. const functions = {
  150. async refreshOnce(once) {
  151. return new Promise((resolve) => {
  152. if (once) {
  153. if (typeof once === "string") {
  154. let res = once.match(/var once = "([\d]+)";/);
  155. if (res && res[1])
  156. resolve(Number(res[1]));
  157. }
  158. if (typeof once === "number")
  159. resolve(once);
  160. }
  161. window.fetchOnce().then((r2) => {
  162. resolve(r2);
  163. });
  164. });
  165. },
  166. clone: (val) => JSON.parse(JSON.stringify(val)),
  167. createList(post, replyList, withRedundList = true) {
  168. post.replyList = replyList;
  169. post.topReplyList = this.clone(replyList).filter((v) => v.thankCount >= window.config.topReplyLoveMinCount).sort((a, b) => b.thankCount - a.thankCount).slice(0, window.config.topReplyCount);
  170. post.replyCount = replyList.length;
  171. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  172. post.nestedReplies = functions.createNestedList(this.clone(replyList), post.topReplyList);
  173. if (withRedundList) {
  174. post.nestedRedundReplies = functions.createNestedRedundantList(this.clone(replyList), post.topReplyList);
  175. }
  176. return post;
  177. },
  178. //获取所有回复
  179. getAllReply(repliesMap = []) {
  180. return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
  181. pre = pre.concat(i.replyList);
  182. return pre;
  183. }, []);
  184. },
  185. //查找子回复
  186. findChildren(item, endList, all, topReplyList) {
  187. var _a;
  188. const fn = (child, endList2, parent) => {
  189. child.level = parent.level + 1;
  190. let rIndex2 = all.findIndex((v) => v.floor === child.floor);
  191. if (rIndex2 > -1) {
  192. all[rIndex2].isUse = true;
  193. }
  194. parent.children.push(this.findChildren(child, endList2, all, topReplyList));
  195. };
  196. item.children = [];
  197. let floorReplyList = [];
  198. for (let i = 0; i < endList.length; i++) {
  199. let currentItem = endList[i];
  200. if (currentItem.isUse)
  201. continue;
  202. if (currentItem.replyFloor === item.floor) {
  203. if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
  204. currentItem.isUse = true;
  205. floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
  206. } else {
  207. currentItem.isWrong = true;
  208. }
  209. }
  210. }
  211. floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
  212. fn(currentItem, endList2, item);
  213. });
  214. let nextMeIndex = endList.findIndex((v) => {
  215. var _a2;
  216. return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
  217. });
  218. let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
  219. for (let i = 0; i < findList.length; i++) {
  220. let currentItem = findList[i];
  221. if (currentItem.isUse)
  222. continue;
  223. if (currentItem.replyUsers.length === 1) {
  224. if (currentItem.replyFloor !== -1) {
  225. if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
  226. continue;
  227. }
  228. }
  229. let endList2 = endList.slice(i + 1);
  230. if (currentItem.username === item.username) {
  231. if (currentItem.replyUsers[0] === item.username) {
  232. fn(currentItem, endList2, item);
  233. }
  234. break;
  235. } else {
  236. if (currentItem.replyUsers[0] === item.username) {
  237. fn(currentItem, endList2, item);
  238. }
  239. }
  240. } else {
  241. if (currentItem.username === item.username)
  242. break;
  243. }
  244. }
  245. item.children = item.children.sort((a, b) => a.floor - b.floor);
  246. item.replyCount = item.children.reduce((a, b) => {
  247. return a + (b.children.length ? b.replyCount + 1 : 1);
  248. }, 0);
  249. let rIndex = topReplyList.findIndex((v) => v.floor === item.floor);
  250. if (rIndex > -1) {
  251. topReplyList[rIndex].children = item.children;
  252. topReplyList[rIndex].replyCount = item.replyCount;
  253. }
  254. return item;
  255. },
  256. //生成嵌套回复
  257. createNestedList(allList = [], topReplyList = []) {
  258. if (!allList.length)
  259. return [];
  260. let list = allList;
  261. let nestedList = [];
  262. list.map((item, index) => {
  263. let startList = list.slice(0, index);
  264. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  265. let endList = list.slice(index + 1);
  266. if (index === 0) {
  267. nestedList.push(this.findChildren(item, endList, list, topReplyList));
  268. } else {
  269. if (!item.isUse) {
  270. let isOneLevelReply = false;
  271. if (item.replyUsers.length) {
  272. if (item.replyUsers.length > 1) {
  273. isOneLevelReply = true;
  274. } else {
  275. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  276. }
  277. } else {
  278. isOneLevelReply = true;
  279. }
  280. if (isOneLevelReply) {
  281. item.level = 0;
  282. nestedList.push(this.findChildren(item, endList, list, topReplyList));
  283. }
  284. }
  285. }
  286. });
  287. return nestedList;
  288. },
  289. //生成嵌套冗余回复
  290. createNestedRedundantList(allList = [], topReplyList) {
  291. if (!allList.length)
  292. return [];
  293. let list = allList;
  294. let nestedList = [];
  295. list.map((item, index) => {
  296. let startList = list.slice(0, index);
  297. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  298. let endList = list.slice(index + 1);
  299. if (index === 0) {
  300. nestedList.push(this.findChildren(item, endList, list, topReplyList));
  301. } else {
  302. if (!item.isUse) {
  303. let isOneLevelReply = false;
  304. if (item.replyUsers.length) {
  305. if (item.replyUsers.length > 1) {
  306. isOneLevelReply = true;
  307. } else {
  308. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  309. }
  310. } else {
  311. isOneLevelReply = true;
  312. }
  313. if (isOneLevelReply) {
  314. item.level = 0;
  315. nestedList.push(this.findChildren(item, endList, list, topReplyList));
  316. }
  317. } else {
  318. let newItem = this.clone(item);
  319. newItem.children = [];
  320. newItem.level = 0;
  321. newItem.isDup = true;
  322. nestedList.push(newItem);
  323. }
  324. }
  325. });
  326. return nestedList;
  327. },
  328. //解析A标签
  329. parseA(a) {
  330. let href = a.href;
  331. let id;
  332. if (href.includes("/t/")) {
  333. id = a.pathname.substring("/t/".length);
  334. }
  335. return { href, id, title: a.innerText };
  336. },
  337. //图片链接转Img标签
  338. checkPhotoLink2Img(dom) {
  339. let replaceImgur = window.config.replaceImgur;
  340. let is_add = false;
  341. let prefix_img = replaceImgur ? DefaultVal.imgurProxy : "";
  342. let imgList = dom.querySelectorAll("img");
  343. imgList.forEach((img) => {
  344. let href = img.src;
  345. if (href.includes("imgur.com")) {
  346. img.setAttribute("originUrl", img.src);
  347. img.setAttribute("notice", "此img标签由V2Next脚本解析");
  348. img.setAttribute("referrerpolicy", "no-referrer");
  349. if (href.includes(".png") || href.includes(".jpg") || href.includes(".jpeg") || href.includes(".gif") || href.includes(".PNG") || href.includes(".JPG") || href.includes(".JPEG") || href.includes(".GIF"))
  350. ;
  351. else {
  352. href = href + ".png";
  353. }
  354. if (!is_add && replaceImgur) {
  355. let meta = document.createElement("meta");
  356. meta.setAttribute("name", "referrer");
  357. meta.setAttribute("content", "no-referrer");
  358. document.getElementsByTagName("head")[0].appendChild(meta);
  359. is_add = true;
  360. }
  361. img.src = prefix_img + href;
  362. }
  363. });
  364. let aList = dom.querySelectorAll("a");
  365. aList.forEach((a) => {
  366. let href = a.href;
  367. if (a.children.length == 0 && a.innerText == href) {
  368. if (href.includes(".png") || href.includes(".jpg") || href.includes(".jpeg") || href.includes(".gif") || href.includes(".PNG") || href.includes(".JPG") || href.includes(".JPEG") || href.includes(".GIF")) {
  369. let img = document.createElement("img");
  370. img.setAttribute("originUrl", a.href);
  371. img.setAttribute("notice", "此img标签由V2Next脚本解析");
  372. img.setAttribute("referrerpolicy", "no-referrer");
  373. if (href.includes("imgur.com")) {
  374. if (!is_add && replaceImgur) {
  375. let meta = document.createElement("meta");
  376. meta.setAttribute("name", "referrer");
  377. meta.setAttribute("content", "no-referrer");
  378. document.getElementsByTagName("head")[0].appendChild(meta);
  379. is_add = true;
  380. }
  381. img.src = prefix_img + href;
  382. } else {
  383. img.src = href;
  384. }
  385. a.innerText = "";
  386. a.append(img);
  387. }
  388. }
  389. });
  390. },
  391. //检测帖子回复长度
  392. async checkPostReplies(id, needOpen = true) {
  393. return new Promise(async (resolve) => {
  394. let res = await functions.getPostDetailByApi(id);
  395. if ((res == null ? void 0 : res.replies) > window.config.maxReplyCountLimit) {
  396. if (needOpen) {
  397. functions.openNewTab(`https://${location.origin}/t/${id}?p=1&script=1`);
  398. }
  399. return resolve(true);
  400. }
  401. resolve(false);
  402. });
  403. },
  404. async sleep(time) {
  405. return new Promise((resolve) => {
  406. setTimeout(resolve, time);
  407. });
  408. },
  409. //打开新标签页
  410. openNewTab(href, active = false) {
  411. let isSafariBrowser = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
  412. if (isSafariBrowser) {
  413. let tempId = "a_blank_" + Date.now();
  414. let a = document.createElement("a");
  415. a.setAttribute("href", href);
  416. a.setAttribute("target", "_blank");
  417. a.setAttribute("id", tempId);
  418. a.setAttribute("script", "1");
  419. if (!document.getElementById(tempId)) {
  420. document.body.appendChild(a);
  421. }
  422. a.click();
  423. } else {
  424. _GM_openInTab(href, { active });
  425. }
  426. },
  427. async cbChecker(val, count = 0) {
  428. if (window.cb) {
  429. window.cb(val);
  430. } else {
  431. while (!window.cb && count < 30) {
  432. await functions.sleep(500);
  433. count++;
  434. }
  435. window.cb && window.cb(val);
  436. }
  437. },
  438. //初始化脚本菜单
  439. initMonkeyMenu() {
  440. try {
  441. _GM_registerMenuCommand("脚本设置", () => {
  442. functions.cbChecker({ type: "openSetting" });
  443. });
  444. _GM_registerMenuCommand("仓库地址", () => {
  445. functions.openNewTab(window.const.git);
  446. });
  447. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  448. } catch (e2) {
  449. console.error("无法使用Tampermonkey");
  450. }
  451. },
  452. feedback() {
  453. functions.openNewTab(DefaultVal.issue);
  454. },
  455. //检测页面类型
  456. checkPageType(a) {
  457. let l = a || window.location;
  458. let data = { pageType: null, pageData: { id: "", pageNo: null }, username: "" };
  459. if (l.pathname === "/") {
  460. data.pageType = PageType.Home;
  461. } else if (l.pathname === "/changes") {
  462. data.pageType = PageType.Changes;
  463. } else if (l.pathname === "/v2hot") {
  464. data.pageType = PageType.Hot;
  465. } else if (l.pathname === "/recent") {
  466. data.pageType = PageType.Changes;
  467. } else if (l.href.match(/.com\/?tab=/)) {
  468. data.pageType = PageType.Home;
  469. } else if (l.href.match(/.com\/go\//)) {
  470. if (!l.href.includes("/links")) {
  471. data.pageType = PageType.Node;
  472. }
  473. } else if (l.href.match(/.com\/member/)) {
  474. data.pageType = PageType.Member;
  475. data.username = l.pathname.replace("/member/", "").replace("/replies", "").replace("/topics", "");
  476. } else {
  477. let r2 = l.href.match(/.com\/t\/([\d]+)/);
  478. if (r2 && !l.pathname.includes("review") && !l.pathname.includes("info")) {
  479. data.pageType = PageType.Post;
  480. data.pageData.id = r2[1];
  481. if (l.search) {
  482. let pr = l.href.match(/\?p=([\d]+)/);
  483. if (pr)
  484. data.pageData.pageNo = Number(pr[1]);
  485. }
  486. }
  487. }
  488. return data;
  489. },
  490. //通过api获取主题详情
  491. getPostDetailByApi(id) {
  492. return new Promise((resolve) => {
  493. fetch(`${location.origin}/api/topics/show.json?id=${id}`).then(async (r2) => {
  494. if (r2.status === 200) {
  495. let res = await r2.json();
  496. if (res) {
  497. let d2 = res[0];
  498. resolve(d2);
  499. }
  500. }
  501. });
  502. });
  503. },
  504. appendPostContent(res, el) {
  505. let a = document.createElement("a");
  506. a.href = res.href;
  507. a.classList.add("post-content");
  508. let div = document.createElement("div");
  509. div.innerHTML = res.content_rendered;
  510. a.append(div);
  511. el.append(a);
  512. const checkHeight2 = () => {
  513. var _a;
  514. if (div.clientHeight < 300) {
  515. a.classList.add("show-all");
  516. } else {
  517. let showMore = document.createElement("div");
  518. showMore.classList.add("show-more");
  519. showMore.innerHTML = "显示更多/收起";
  520. showMore.onclick = function(e2) {
  521. e2.stopPropagation();
  522. a.classList.toggle("show-all");
  523. };
  524. (_a = a.parentNode) == null ? void 0 : _a.append(showMore);
  525. }
  526. };
  527. checkHeight2();
  528. },
  529. //从本地读取配置
  530. initConfig() {
  531. let configStr = localStorage.getItem("v2ex-config");
  532. let configMap = {};
  533. let configObj = {};
  534. let userName = window.user.username || "default";
  535. if (configStr) {
  536. configMap = JSON.parse(configStr);
  537. configObj = configMap[userName];
  538. if (configObj) {
  539. window.config = functions.deepAssign(window.config, configObj);
  540. }
  541. }
  542. configMap[userName] = window.config;
  543. localStorage.setItem("v2ex-config", JSON.stringify(configMap));
  544. },
  545. deepAssign(...arg) {
  546. let name, options, src, copy;
  547. let length = arguments.length;
  548. let i = 1;
  549. let target = arguments[0] || {};
  550. if (typeof target !== "object") {
  551. target = {};
  552. }
  553. for (; i < length; i++) {
  554. options = arguments[i];
  555. if (options != null) {
  556. for (name in options) {
  557. src = target[name];
  558. copy = options[name];
  559. if (copy && typeof copy == "object") {
  560. target[name] = this.deepAssign(src, copy);
  561. } else if (copy !== void 0) {
  562. target[name] = copy;
  563. }
  564. }
  565. }
  566. }
  567. return target;
  568. },
  569. //生成dom,从html字符串
  570. genDomFromHtmlString(htmlText) {
  571. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  572. let body = document.createElement("html");
  573. body.innerHTML = bodyText[0];
  574. return body;
  575. },
  576. stopEvent(e2) {
  577. e2.preventDefault();
  578. e2.stopPropagation();
  579. }
  580. };
  581. const DefaultPost = {
  582. allReplyUsers: [],
  583. content_rendered: "",
  584. createDate: "",
  585. createDateAgo: "",
  586. lastReplyDate: "",
  587. lastReplyUsername: "",
  588. fr: "",
  589. replyList: [],
  590. topReplyList: [],
  591. nestedReplies: [],
  592. nestedRedundReplies: [],
  593. username: "",
  594. url: "",
  595. href: "",
  596. member: {
  597. avatar: "",
  598. username: ""
  599. },
  600. node: {
  601. title: "",
  602. url: ""
  603. },
  604. headerTemplate: "",
  605. title: "",
  606. id: "",
  607. type: "post",
  608. once: "",
  609. replyCount: 0,
  610. clickCount: 0,
  611. thankCount: 0,
  612. collectCount: 0,
  613. lastReadFloor: 0,
  614. isFavorite: false,
  615. isIgnore: false,
  616. isThanked: false,
  617. isReport: false,
  618. inList: false
  619. };
  620. const getDefaultPost = (val = {}) => {
  621. return Object.assign(functions.clone(DefaultPost), val);
  622. };
  623. const DefaultUser = {
  624. tagPrefix: "--用户标签--",
  625. tags: {},
  626. tagsId: "",
  627. username: "",
  628. avatar: "",
  629. readPrefix: "--已读楼层--",
  630. readNoteItemId: "",
  631. readList: {},
  632. imgurPrefix: "--imgur图片删除hash--",
  633. imgurList: {},
  634. imgurNoteId: "",
  635. configPrefix: "--config--",
  636. configNoteId: ""
  637. };
  638. const DefaultVal = {
  639. pageType: void 0,
  640. pageData: { pageNo: 1 },
  641. targetUserName: "",
  642. currentVersion: 5,
  643. cb: null,
  644. git: "https://github.com/zyronon/V2Next",
  645. shortGit: "zyronon/V2Next",
  646. issue: "https://github.com/zyronon/V2Next/issues",
  647. pcLog: "https://greasyfork.org/zh-CN/scripts/458024/versions",
  648. pcScript: "https://greasyfork.org/zh-CN/scripts/458024",
  649. mobileScript: "https://github.com/zyronon/V2Next/releases",
  650. homeUrl: "https://vtonext.vercel.app/",
  651. hotUrl: "https://v2hotlist.vercel.app/hot/",
  652. imgurProxy: "https://img.noobzone.ru/getimg.php?url="
  653. };
  654. function getDefaultConfig(val = {}) {
  655. return Object.assign({
  656. showToolbar: true,
  657. autoOpenDetail: true,
  658. openTag: false,
  659. //给用户打标签
  660. clickPostItemOpenDetail: true,
  661. closePostDetailBySpace: true,
  662. //点击空白处关闭详情
  663. contentAutoCollapse: true,
  664. //正文超长自动折叠
  665. viewType: "table",
  666. commentDisplayType: CommentDisplayType.FloorInFloorNoCallUser,
  667. newTabOpen: false,
  668. //新标签打开
  669. newTabOpenActive: false,
  670. base64: true,
  671. //base功能
  672. sov2ex: false,
  673. postWidth: "",
  674. showTopReply: true,
  675. topReplyLoveMinCount: 3,
  676. topReplyCount: 5,
  677. autoJumpLastReadFloor: false,
  678. rememberLastReadFloor: false,
  679. autoSignin: true,
  680. customBgColor: "",
  681. version: DefaultVal.currentVersion,
  682. collectBrowserNotice: false,
  683. fontSizeType: "normal",
  684. notice: {
  685. uid: "",
  686. text: "",
  687. ddWebhook: "",
  688. takeOverNoticePage: true,
  689. whenNewNoticeGlimmer: false,
  690. loopCheckNotice: false,
  691. loopCheckNoticeInterval: 5
  692. },
  693. replaceImgur: false,
  694. maxReplyCountLimit: 400
  695. }, val);
  696. }
  697. const emojiEmoticons = [
  698. {
  699. title: "常用",
  700. list: [
  701. "😅",
  702. "😭",
  703. "😂",
  704. "🥰",
  705. "😰",
  706. "🤡",
  707. "👀",
  708. "🐴",
  709. "🐶",
  710. "❓",
  711. "❤️",
  712. "💔",
  713. "⭐",
  714. "🔥",
  715. "💩",
  716. "🔞",
  717. "⚠️",
  718. "🎁",
  719. "🎉"
  720. ]
  721. },
  722. {
  723. title: "小黄脸",
  724. list: [
  725. "😀",
  726. "😁",
  727. "😂",
  728. "🤣",
  729. "😅",
  730. "😊",
  731. "😋",
  732. "😘",
  733. "🥰",
  734. "😗",
  735. "🤩",
  736. "🤔",
  737. "🤨",
  738. "😐",
  739. "😑",
  740. "🙄",
  741. "😏",
  742. "😪",
  743. "😫",
  744. "🥱",
  745. "😜",
  746. "😒",
  747. "😔",
  748. "😨",
  749. "😰",
  750. "😱",
  751. "🥵",
  752. "😡",
  753. "🥳",
  754. "🥺",
  755. "🤭",
  756. "🧐",
  757. "😎",
  758. "🤓",
  759. "😭",
  760. "🤑",
  761. "🤮"
  762. ]
  763. },
  764. {
  765. title: "手势",
  766. list: [
  767. "🤏",
  768. "👉",
  769. "✌️",
  770. "👌",
  771. "👍",
  772. "👎",
  773. "🤝",
  774. "🙏",
  775. "👏"
  776. ]
  777. },
  778. {
  779. title: "其他",
  780. list: ["🔞", "👻", "🤡", "🐔", "👀", "💩", "🐴", "🦄", "🐧", "🐶"]
  781. }
  782. ];
  783. const classicsEmoticons = [
  784. {
  785. name: "[狗头]",
  786. low: "https://i.imgur.com/io2SM1h.png",
  787. high: "https://i.imgur.com/0icl60r.png"
  788. },
  789. {
  790. name: "[doge]",
  791. low: "https://i.imgur.com/duWRpIu.png",
  792. high: "https://i.imgur.com/HyphI6d.png"
  793. },
  794. {
  795. name: "[受虐滑稽]",
  796. low: "https://i.imgur.com/Iy0taMy.png",
  797. high: "https://i.imgur.com/PS1pxd9.png"
  798. },
  799. {
  800. name: "[马]",
  801. low: "https://i.imgur.com/8EKZv7I.png",
  802. high: "https://i.imgur.com/ANFUX52.png"
  803. },
  804. {
  805. name: "[二哈]",
  806. low: "https://i.imgur.com/XKj1Tkx.png",
  807. high: "https://i.imgur.com/dOeP4XD.png"
  808. },
  809. {
  810. name: "[舔屏]",
  811. low: "https://i.imgur.com/Cvl7dyN.png",
  812. high: "https://i.imgur.com/LmETy9N.png"
  813. },
  814. {
  815. name: "[辣眼睛]",
  816. low: "https://i.imgur.com/cPNPYD5.png",
  817. high: "https://i.imgur.com/3fSUmi8.png"
  818. },
  819. {
  820. name: "[吃瓜]",
  821. low: "https://i.imgur.com/ee8Lq7H.png",
  822. high: "https://i.imgur.com/0L26og9.png"
  823. },
  824. {
  825. name: "[不高兴]",
  826. low: "https://i.imgur.com/huX6coX.png",
  827. high: "https://i.imgur.com/N7JEuvc.png"
  828. },
  829. // {
  830. // name: '[呵呵]',
  831. // low: 'https://i.imgur.com/RvoLAbX.png',
  832. // high: 'https://i.imgur.com/xSzIqrK.png'
  833. // },
  834. {
  835. name: "[真棒]",
  836. low: "https://i.imgur.com/xr1UOz1.png",
  837. high: "https://i.imgur.com/w8YEw9Q.png"
  838. },
  839. {
  840. name: "[鄙视]",
  841. low: "https://i.imgur.com/u6jlqVq.png",
  842. high: "https://i.imgur.com/8JFNANq.png"
  843. },
  844. {
  845. name: "[疑问]",
  846. low: "https://i.imgur.com/F29pmQ6.png",
  847. high: "https://i.imgur.com/EbbTQAR.png"
  848. },
  849. {
  850. name: "[吐舌]",
  851. low: "https://i.imgur.com/InmIzl9.png",
  852. high: "https://i.imgur.com/Ovj56Cd.png"
  853. },
  854. // {
  855. // name: '[嘲笑]',
  856. // low: 'https://i.imgur.com/BaWcsMR.png',
  857. // high: 'https://i.imgur.com/0OGfJw4.png'
  858. // },
  859. // {
  860. // name: '[滑稽]',
  861. // low: 'https://i.imgur.com/lmbN0yI.png',
  862. // high: 'https://i.imgur.com/Pc0wH85.png'
  863. // },
  864. {
  865. name: "[笑眼]",
  866. low: "https://i.imgur.com/ZveiiGy.png",
  867. high: "https://i.imgur.com/PI1CfEr.png"
  868. },
  869. // {
  870. // name: '[狂汗]',
  871. // low: 'https://i.imgur.com/veWihk6.png',
  872. // high: 'https://i.imgur.com/3LtHdQv.png'
  873. // },
  874. {
  875. name: "[大哭]",
  876. low: "https://i.imgur.com/hu4oR6C.png",
  877. high: "https://i.imgur.com/b4X9XLE.png"
  878. },
  879. {
  880. name: "[喷]",
  881. low: "https://i.imgur.com/bkw3VRr.png",
  882. high: "https://i.imgur.com/wnZL13L.png"
  883. },
  884. {
  885. name: "[苦笑]",
  886. low: "https://i.imgur.com/VUWFktU.png",
  887. high: "https://i.imgur.com/NAfspZ1.png"
  888. },
  889. {
  890. name: "[喝酒]",
  891. low: "https://i.imgur.com/2ZZSapE.png",
  892. high: "https://i.imgur.com/rVbSVak.png"
  893. },
  894. {
  895. name: "[捂脸]",
  896. low: "https://i.imgur.com/krir4IG.png",
  897. high: "https://i.imgur.com/qqBqgVm.png"
  898. },
  899. // {
  900. // name: '[呕]',
  901. // low: 'https://i.imgur.com/6CUiUxv.png',
  902. // high: 'https://i.imgur.com/kgdxRsG.png'
  903. // },
  904. {
  905. name: "[阴险]",
  906. low: "https://i.imgur.com/MA8YqTP.png",
  907. high: "https://i.imgur.com/e94jbaT.png"
  908. },
  909. {
  910. name: "[怒]",
  911. low: "https://i.imgur.com/n4kWfGB.png",
  912. high: "https://i.imgur.com/iMXxNxh.png"
  913. }
  914. // {
  915. // name: '[衰]',
  916. // low: 'https://i.imgur.com/voHFDyQ.png',
  917. // high: 'https://i.imgur.com/XffE6gu.png'
  918. // },
  919. // {
  920. // name: '[合十]',
  921. // low: 'https://i.imgur.com/I8x3ang.png',
  922. // high: 'https://i.imgur.com/T4rJVee.png'
  923. // },
  924. // {
  925. // name: '[赞]',
  926. // low: 'https://i.imgur.com/lG44yUl.png',
  927. // high: 'https://i.imgur.com/AoF5PLp.png'
  928. // },
  929. // {
  930. // name: '[踩]',
  931. // low: 'https://i.imgur.com/cJp0uKZ.png',
  932. // high: 'https://i.imgur.com/1XYGfXj.png'
  933. // },
  934. // {
  935. // name: '[爱心]',
  936. // low: 'https://i.imgur.com/sLENaF5.png',
  937. // high: 'https://i.imgur.com/dND56oX.png'
  938. // },
  939. //
  940. // {
  941. // name: '[心碎]',
  942. // low: 'https://i.imgur.com/AZxJzve.png',
  943. // high: 'https://i.imgur.com/RiUsPci.png'
  944. // },
  945. ];
  946. const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
  947. const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
  948. const colonSeparated = value.split(":");
  949. if (value.slice(0, 1) === "@") {
  950. if (colonSeparated.length < 2 || colonSeparated.length > 3) {
  951. return null;
  952. }
  953. provider = colonSeparated.shift().slice(1);
  954. }
  955. if (colonSeparated.length > 3 || !colonSeparated.length) {
  956. return null;
  957. }
  958. if (colonSeparated.length > 1) {
  959. const name2 = colonSeparated.pop();
  960. const prefix = colonSeparated.pop();
  961. const result = {
  962. // Allow provider without '@': "provider:prefix:name"
  963. provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
  964. prefix,
  965. name: name2
  966. };
  967. return validate && !validateIconName(result) ? null : result;
  968. }
  969. const name = colonSeparated[0];
  970. const dashSeparated = name.split("-");
  971. if (dashSeparated.length > 1) {
  972. const result = {
  973. provider,
  974. prefix: dashSeparated.shift(),
  975. name: dashSeparated.join("-")
  976. };
  977. return validate && !validateIconName(result) ? null : result;
  978. }
  979. if (allowSimpleName && provider === "") {
  980. const result = {
  981. provider,
  982. prefix: "",
  983. name
  984. };
  985. return validate && !validateIconName(result, allowSimpleName) ? null : result;
  986. }
  987. return null;
  988. };
  989. const validateIconName = (icon, allowSimpleName) => {
  990. if (!icon) {
  991. return false;
  992. }
  993. return !!((icon.provider === "" || icon.provider.match(matchIconName)) && (allowSimpleName && icon.prefix === "" || icon.prefix.match(matchIconName)) && icon.name.match(matchIconName));
  994. };
  995. const defaultIconDimensions = Object.freeze(
  996. {
  997. left: 0,
  998. top: 0,
  999. width: 16,
  1000. height: 16
  1001. }
  1002. );
  1003. const defaultIconTransformations = Object.freeze({
  1004. rotate: 0,
  1005. vFlip: false,
  1006. hFlip: false
  1007. });
  1008. const defaultIconProps = Object.freeze({
  1009. ...defaultIconDimensions,
  1010. ...defaultIconTransformations
  1011. });
  1012. const defaultExtendedIconProps = Object.freeze({
  1013. ...defaultIconProps,
  1014. body: "",
  1015. hidden: false
  1016. });
  1017. function mergeIconTransformations(obj1, obj2) {
  1018. const result = {};
  1019. if (!obj1.hFlip !== !obj2.hFlip) {
  1020. result.hFlip = true;
  1021. }
  1022. if (!obj1.vFlip !== !obj2.vFlip) {
  1023. result.vFlip = true;
  1024. }
  1025. const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
  1026. if (rotate) {
  1027. result.rotate = rotate;
  1028. }
  1029. return result;
  1030. }
  1031. function mergeIconData(parent, child) {
  1032. const result = mergeIconTransformations(parent, child);
  1033. for (const key in defaultExtendedIconProps) {
  1034. if (key in defaultIconTransformations) {
  1035. if (key in parent && !(key in result)) {
  1036. result[key] = defaultIconTransformations[key];
  1037. }
  1038. } else if (key in child) {
  1039. result[key] = child[key];
  1040. } else if (key in parent) {
  1041. result[key] = parent[key];
  1042. }
  1043. }
  1044. return result;
  1045. }
  1046. function getIconsTree(data, names) {
  1047. const icons = data.icons;
  1048. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  1049. const resolved = /* @__PURE__ */ Object.create(null);
  1050. function resolve(name) {
  1051. if (icons[name]) {
  1052. return resolved[name] = [];
  1053. }
  1054. if (!(name in resolved)) {
  1055. resolved[name] = null;
  1056. const parent = aliases[name] && aliases[name].parent;
  1057. const value = parent && resolve(parent);
  1058. if (value) {
  1059. resolved[name] = [parent].concat(value);
  1060. }
  1061. }
  1062. return resolved[name];
  1063. }
  1064. (names || Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);
  1065. return resolved;
  1066. }
  1067. function internalGetIconData(data, name, tree) {
  1068. const icons = data.icons;
  1069. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  1070. let currentProps = {};
  1071. function parse(name2) {
  1072. currentProps = mergeIconData(
  1073. icons[name2] || aliases[name2],
  1074. currentProps
  1075. );
  1076. }
  1077. parse(name);
  1078. tree.forEach(parse);
  1079. return mergeIconData(data, currentProps);
  1080. }
  1081. function parseIconSet(data, callback) {
  1082. const names = [];
  1083. if (typeof data !== "object" || typeof data.icons !== "object") {
  1084. return names;
  1085. }
  1086. if (data.not_found instanceof Array) {
  1087. data.not_found.forEach((name) => {
  1088. callback(name, null);
  1089. names.push(name);
  1090. });
  1091. }
  1092. const tree = getIconsTree(data);
  1093. for (const name in tree) {
  1094. const item = tree[name];
  1095. if (item) {
  1096. callback(name, internalGetIconData(data, name, item));
  1097. names.push(name);
  1098. }
  1099. }
  1100. return names;
  1101. }
  1102. const optionalPropertyDefaults = {
  1103. provider: "",
  1104. aliases: {},
  1105. not_found: {},
  1106. ...defaultIconDimensions
  1107. };
  1108. function checkOptionalProps(item, defaults) {
  1109. for (const prop in defaults) {
  1110. if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
  1111. return false;
  1112. }
  1113. }
  1114. return true;
  1115. }
  1116. function quicklyValidateIconSet(obj) {
  1117. if (typeof obj !== "object" || obj === null) {
  1118. return null;
  1119. }
  1120. const data = obj;
  1121. if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
  1122. return null;
  1123. }
  1124. if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
  1125. return null;
  1126. }
  1127. const icons = data.icons;
  1128. for (const name in icons) {
  1129. const icon = icons[name];
  1130. if (!name.match(matchIconName) || typeof icon.body !== "string" || !checkOptionalProps(
  1131. icon,
  1132. defaultExtendedIconProps
  1133. )) {
  1134. return null;
  1135. }
  1136. }
  1137. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  1138. for (const name in aliases) {
  1139. const icon = aliases[name];
  1140. const parent = icon.parent;
  1141. if (!name.match(matchIconName) || typeof parent !== "string" || !icons[parent] && !aliases[parent] || !checkOptionalProps(
  1142. icon,
  1143. defaultExtendedIconProps
  1144. )) {
  1145. return null;
  1146. }
  1147. }
  1148. return data;
  1149. }
  1150. const dataStorage = /* @__PURE__ */ Object.create(null);
  1151. function newStorage(provider, prefix) {
  1152. return {
  1153. provider,
  1154. prefix,
  1155. icons: /* @__PURE__ */ Object.create(null),
  1156. missing: /* @__PURE__ */ new Set()
  1157. };
  1158. }
  1159. function getStorage(provider, prefix) {
  1160. const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));
  1161. return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));
  1162. }
  1163. function addIconSet(storage2, data) {
  1164. if (!quicklyValidateIconSet(data)) {
  1165. return [];
  1166. }
  1167. return parseIconSet(data, (name, icon) => {
  1168. if (icon) {
  1169. storage2.icons[name] = icon;
  1170. } else {
  1171. storage2.missing.add(name);
  1172. }
  1173. });
  1174. }
  1175. function addIconToStorage(storage2, name, icon) {
  1176. try {
  1177. if (typeof icon.body === "string") {
  1178. storage2.icons[name] = { ...icon };
  1179. return true;
  1180. }
  1181. } catch (err) {
  1182. }
  1183. return false;
  1184. }
  1185. let simpleNames = false;
  1186. function allowSimpleNames(allow) {
  1187. if (typeof allow === "boolean") {
  1188. simpleNames = allow;
  1189. }
  1190. return simpleNames;
  1191. }
  1192. function getIconData(name) {
  1193. const icon = typeof name === "string" ? stringToIcon(name, true, simpleNames) : name;
  1194. if (icon) {
  1195. const storage2 = getStorage(icon.provider, icon.prefix);
  1196. const iconName = icon.name;
  1197. return storage2.icons[iconName] || (storage2.missing.has(iconName) ? null : void 0);
  1198. }
  1199. }
  1200. function addIcon(name, data) {
  1201. const icon = stringToIcon(name, true, simpleNames);
  1202. if (!icon) {
  1203. return false;
  1204. }
  1205. const storage2 = getStorage(icon.provider, icon.prefix);
  1206. return addIconToStorage(storage2, icon.name, data);
  1207. }
  1208. function addCollection(data, provider) {
  1209. if (typeof data !== "object") {
  1210. return false;
  1211. }
  1212. if (typeof provider !== "string") {
  1213. provider = data.provider || "";
  1214. }
  1215. if (simpleNames && !provider && !data.prefix) {
  1216. let added = false;
  1217. if (quicklyValidateIconSet(data)) {
  1218. data.prefix = "";
  1219. parseIconSet(data, (name, icon) => {
  1220. if (icon && addIcon(name, icon)) {
  1221. added = true;
  1222. }
  1223. });
  1224. }
  1225. return added;
  1226. }
  1227. const prefix = data.prefix;
  1228. if (!validateIconName({
  1229. provider,
  1230. prefix,
  1231. name: "a"
  1232. })) {
  1233. return false;
  1234. }
  1235. const storage2 = getStorage(provider, prefix);
  1236. return !!addIconSet(storage2, data);
  1237. }
  1238. const defaultIconSizeCustomisations = Object.freeze({
  1239. width: null,
  1240. height: null
  1241. });
  1242. const defaultIconCustomisations = Object.freeze({
  1243. // Dimensions
  1244. ...defaultIconSizeCustomisations,
  1245. // Transformations
  1246. ...defaultIconTransformations
  1247. });
  1248. const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
  1249. const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
  1250. function calculateSize(size, ratio, precision) {
  1251. if (ratio === 1) {
  1252. return size;
  1253. }
  1254. precision = precision || 100;
  1255. if (typeof size === "number") {
  1256. return Math.ceil(size * ratio * precision) / precision;
  1257. }
  1258. if (typeof size !== "string") {
  1259. return size;
  1260. }
  1261. const oldParts = size.split(unitsSplit);
  1262. if (oldParts === null || !oldParts.length) {
  1263. return size;
  1264. }
  1265. const newParts = [];
  1266. let code = oldParts.shift();
  1267. let isNumber = unitsTest.test(code);
  1268. while (true) {
  1269. if (isNumber) {
  1270. const num = parseFloat(code);
  1271. if (isNaN(num)) {
  1272. newParts.push(code);
  1273. } else {
  1274. newParts.push(Math.ceil(num * ratio * precision) / precision);
  1275. }
  1276. } else {
  1277. newParts.push(code);
  1278. }
  1279. code = oldParts.shift();
  1280. if (code === void 0) {
  1281. return newParts.join("");
  1282. }
  1283. isNumber = !isNumber;
  1284. }
  1285. }
  1286. const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
  1287. function iconToSVG(icon, customisations) {
  1288. const fullIcon = {
  1289. ...defaultIconProps,
  1290. ...icon
  1291. };
  1292. const fullCustomisations = {
  1293. ...defaultIconCustomisations,
  1294. ...customisations
  1295. };
  1296. const box = {
  1297. left: fullIcon.left,
  1298. top: fullIcon.top,
  1299. width: fullIcon.width,
  1300. height: fullIcon.height
  1301. };
  1302. let body = fullIcon.body;
  1303. [fullIcon, fullCustomisations].forEach((props) => {
  1304. const transformations = [];
  1305. const hFlip = props.hFlip;
  1306. const vFlip = props.vFlip;
  1307. let rotation = props.rotate;
  1308. if (hFlip) {
  1309. if (vFlip) {
  1310. rotation += 2;
  1311. } else {
  1312. transformations.push(
  1313. "translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
  1314. );
  1315. transformations.push("scale(-1 1)");
  1316. box.top = box.left = 0;
  1317. }
  1318. } else if (vFlip) {
  1319. transformations.push(
  1320. "translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
  1321. );
  1322. transformations.push("scale(1 -1)");
  1323. box.top = box.left = 0;
  1324. }
  1325. let tempValue;
  1326. if (rotation < 0) {
  1327. rotation -= Math.floor(rotation / 4) * 4;
  1328. }
  1329. rotation = rotation % 4;
  1330. switch (rotation) {
  1331. case 1:
  1332. tempValue = box.height / 2 + box.top;
  1333. transformations.unshift(
  1334. "rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
  1335. );
  1336. break;
  1337. case 2:
  1338. transformations.unshift(
  1339. "rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
  1340. );
  1341. break;
  1342. case 3:
  1343. tempValue = box.width / 2 + box.left;
  1344. transformations.unshift(
  1345. "rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
  1346. );
  1347. break;
  1348. }
  1349. if (rotation % 2 === 1) {
  1350. if (box.left !== box.top) {
  1351. tempValue = box.left;
  1352. box.left = box.top;
  1353. box.top = tempValue;
  1354. }
  1355. if (box.width !== box.height) {
  1356. tempValue = box.width;
  1357. box.width = box.height;
  1358. box.height = tempValue;
  1359. }
  1360. }
  1361. if (transformations.length) {
  1362. body = '<g transform="' + transformations.join(" ") + '">' + body + "</g>";
  1363. }
  1364. });
  1365. const customisationsWidth = fullCustomisations.width;
  1366. const customisationsHeight = fullCustomisations.height;
  1367. const boxWidth = box.width;
  1368. const boxHeight = box.height;
  1369. let width;
  1370. let height;
  1371. if (customisationsWidth === null) {
  1372. height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
  1373. width = calculateSize(height, boxWidth / boxHeight);
  1374. } else {
  1375. width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
  1376. height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
  1377. }
  1378. const attributes = {};
  1379. const setAttr = (prop, value) => {
  1380. if (!isUnsetKeyword(value)) {
  1381. attributes[prop] = value.toString();
  1382. }
  1383. };
  1384. setAttr("width", width);
  1385. setAttr("height", height);
  1386. attributes.viewBox = box.left.toString() + " " + box.top.toString() + " " + boxWidth.toString() + " " + boxHeight.toString();
  1387. return {
  1388. attributes,
  1389. body
  1390. };
  1391. }
  1392. const regex = /\sid="(\S+)"/g;
  1393. const randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
  1394. let counter = 0;
  1395. function replaceIDs(body, prefix = randomPrefix) {
  1396. const ids = [];
  1397. let match;
  1398. while (match = regex.exec(body)) {
  1399. ids.push(match[1]);
  1400. }
  1401. if (!ids.length) {
  1402. return body;
  1403. }
  1404. const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
  1405. ids.forEach((id) => {
  1406. const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
  1407. const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  1408. body = body.replace(
  1409. // Allowed characters before id: [#;"]
  1410. // Allowed characters after id: [)"], .[a-z]
  1411. new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"),
  1412. "$1" + newID + suffix + "$3"
  1413. );
  1414. });
  1415. body = body.replace(new RegExp(suffix, "g"), "");
  1416. return body;
  1417. }
  1418. const storage = /* @__PURE__ */ Object.create(null);
  1419. function setAPIModule(provider, item) {
  1420. storage[provider] = item;
  1421. }
  1422. function getAPIModule(provider) {
  1423. return storage[provider] || storage[""];
  1424. }
  1425. function createAPIConfig(source) {
  1426. let resources;
  1427. if (typeof source.resources === "string") {
  1428. resources = [source.resources];
  1429. } else {
  1430. resources = source.resources;
  1431. if (!(resources instanceof Array) || !resources.length) {
  1432. return null;
  1433. }
  1434. }
  1435. const result = {
  1436. // API hosts
  1437. resources,
  1438. // Root path
  1439. path: source.path || "/",
  1440. // URL length limit
  1441. maxURL: source.maxURL || 500,
  1442. // Timeout before next host is used.
  1443. rotate: source.rotate || 750,
  1444. // Timeout before failing query.
  1445. timeout: source.timeout || 5e3,
  1446. // Randomise default API end point.
  1447. random: source.random === true,
  1448. // Start index
  1449. index: source.index || 0,
  1450. // Receive data after time out (used if time out kicks in first, then API module sends data anyway).
  1451. dataAfterTimeout: source.dataAfterTimeout !== false
  1452. };
  1453. return result;
  1454. }
  1455. const configStorage = /* @__PURE__ */ Object.create(null);
  1456. const fallBackAPISources = [
  1457. "https://api.simplesvg.com",
  1458. "https://api.unisvg.com"
  1459. ];
  1460. const fallBackAPI = [];
  1461. while (fallBackAPISources.length > 0) {
  1462. if (fallBackAPISources.length === 1) {
  1463. fallBackAPI.push(fallBackAPISources.shift());
  1464. } else {
  1465. if (Math.random() > 0.5) {
  1466. fallBackAPI.push(fallBackAPISources.shift());
  1467. } else {
  1468. fallBackAPI.push(fallBackAPISources.pop());
  1469. }
  1470. }
  1471. }
  1472. configStorage[""] = createAPIConfig({
  1473. resources: ["https://api.iconify.design"].concat(fallBackAPI)
  1474. });
  1475. function addAPIProvider(provider, customConfig) {
  1476. const config2 = createAPIConfig(customConfig);
  1477. if (config2 === null) {
  1478. return false;
  1479. }
  1480. configStorage[provider] = config2;
  1481. return true;
  1482. }
  1483. function getAPIConfig(provider) {
  1484. return configStorage[provider];
  1485. }
  1486. const detectFetch = () => {
  1487. let callback;
  1488. try {
  1489. callback = fetch;
  1490. if (typeof callback === "function") {
  1491. return callback;
  1492. }
  1493. } catch (err) {
  1494. }
  1495. };
  1496. let fetchModule = detectFetch();
  1497. function calculateMaxLength(provider, prefix) {
  1498. const config2 = getAPIConfig(provider);
  1499. if (!config2) {
  1500. return 0;
  1501. }
  1502. let result;
  1503. if (!config2.maxURL) {
  1504. result = 0;
  1505. } else {
  1506. let maxHostLength = 0;
  1507. config2.resources.forEach((item) => {
  1508. const host = item;
  1509. maxHostLength = Math.max(maxHostLength, host.length);
  1510. });
  1511. const url = prefix + ".json?icons=";
  1512. result = config2.maxURL - maxHostLength - config2.path.length - url.length;
  1513. }
  1514. return result;
  1515. }
  1516. function shouldAbort(status) {
  1517. return status === 404;
  1518. }
  1519. const prepare = (provider, prefix, icons) => {
  1520. const results = [];
  1521. const maxLength = calculateMaxLength(provider, prefix);
  1522. const type = "icons";
  1523. let item = {
  1524. type,
  1525. provider,
  1526. prefix,
  1527. icons: []
  1528. };
  1529. let length = 0;
  1530. icons.forEach((name, index) => {
  1531. length += name.length + 1;
  1532. if (length >= maxLength && index > 0) {
  1533. results.push(item);
  1534. item = {
  1535. type,
  1536. provider,
  1537. prefix,
  1538. icons: []
  1539. };
  1540. length = name.length;
  1541. }
  1542. item.icons.push(name);
  1543. });
  1544. results.push(item);
  1545. return results;
  1546. };
  1547. function getPath(provider) {
  1548. if (typeof provider === "string") {
  1549. const config2 = getAPIConfig(provider);
  1550. if (config2) {
  1551. return config2.path;
  1552. }
  1553. }
  1554. return "/";
  1555. }
  1556. const send = (host, params, callback) => {
  1557. if (!fetchModule) {
  1558. callback("abort", 424);
  1559. return;
  1560. }
  1561. let path = getPath(params.provider);
  1562. switch (params.type) {
  1563. case "icons": {
  1564. const prefix = params.prefix;
  1565. const icons = params.icons;
  1566. const iconsList = icons.join(",");
  1567. const urlParams = new URLSearchParams({
  1568. icons: iconsList
  1569. });
  1570. path += prefix + ".json?" + urlParams.toString();
  1571. break;
  1572. }
  1573. case "custom": {
  1574. const uri = params.uri;
  1575. path += uri.slice(0, 1) === "/" ? uri.slice(1) : uri;
  1576. break;
  1577. }
  1578. default:
  1579. callback("abort", 400);
  1580. return;
  1581. }
  1582. let defaultError = 503;
  1583. fetchModule(host + path).then((response) => {
  1584. const status = response.status;
  1585. if (status !== 200) {
  1586. setTimeout(() => {
  1587. callback(shouldAbort(status) ? "abort" : "next", status);
  1588. });
  1589. return;
  1590. }
  1591. defaultError = 501;
  1592. return response.json();
  1593. }).then((data) => {
  1594. if (typeof data !== "object" || data === null) {
  1595. setTimeout(() => {
  1596. if (data === 404) {
  1597. callback("abort", data);
  1598. } else {
  1599. callback("next", defaultError);
  1600. }
  1601. });
  1602. return;
  1603. }
  1604. setTimeout(() => {
  1605. callback("success", data);
  1606. });
  1607. }).catch(() => {
  1608. callback("next", defaultError);
  1609. });
  1610. };
  1611. const fetchAPIModule = {
  1612. prepare,
  1613. send
  1614. };
  1615. function sortIcons(icons) {
  1616. const result = {
  1617. loaded: [],
  1618. missing: [],
  1619. pending: []
  1620. };
  1621. const storage2 = /* @__PURE__ */ Object.create(null);
  1622. icons.sort((a, b) => {
  1623. if (a.provider !== b.provider) {
  1624. return a.provider.localeCompare(b.provider);
  1625. }
  1626. if (a.prefix !== b.prefix) {
  1627. return a.prefix.localeCompare(b.prefix);
  1628. }
  1629. return a.name.localeCompare(b.name);
  1630. });
  1631. let lastIcon = {
  1632. provider: "",
  1633. prefix: "",
  1634. name: ""
  1635. };
  1636. icons.forEach((icon) => {
  1637. if (lastIcon.name === icon.name && lastIcon.prefix === icon.prefix && lastIcon.provider === icon.provider) {
  1638. return;
  1639. }
  1640. lastIcon = icon;
  1641. const provider = icon.provider;
  1642. const prefix = icon.prefix;
  1643. const name = icon.name;
  1644. const providerStorage = storage2[provider] || (storage2[provider] = /* @__PURE__ */ Object.create(null));
  1645. const localStorage2 = providerStorage[prefix] || (providerStorage[prefix] = getStorage(provider, prefix));
  1646. let list;
  1647. if (name in localStorage2.icons) {
  1648. list = result.loaded;
  1649. } else if (prefix === "" || localStorage2.missing.has(name)) {
  1650. list = result.missing;
  1651. } else {
  1652. list = result.pending;
  1653. }
  1654. const item = {
  1655. provider,
  1656. prefix,
  1657. name
  1658. };
  1659. list.push(item);
  1660. });
  1661. return result;
  1662. }
  1663. function removeCallback(storages, id) {
  1664. storages.forEach((storage2) => {
  1665. const items = storage2.loaderCallbacks;
  1666. if (items) {
  1667. storage2.loaderCallbacks = items.filter((row) => row.id !== id);
  1668. }
  1669. });
  1670. }
  1671. function updateCallbacks(storage2) {
  1672. if (!storage2.pendingCallbacksFlag) {
  1673. storage2.pendingCallbacksFlag = true;
  1674. setTimeout(() => {
  1675. storage2.pendingCallbacksFlag = false;
  1676. const items = storage2.loaderCallbacks ? storage2.loaderCallbacks.slice(0) : [];
  1677. if (!items.length) {
  1678. return;
  1679. }
  1680. let hasPending = false;
  1681. const provider = storage2.provider;
  1682. const prefix = storage2.prefix;
  1683. items.forEach((item) => {
  1684. const icons = item.icons;
  1685. const oldLength = icons.pending.length;
  1686. icons.pending = icons.pending.filter((icon) => {
  1687. if (icon.prefix !== prefix) {
  1688. return true;
  1689. }
  1690. const name = icon.name;
  1691. if (storage2.icons[name]) {
  1692. icons.loaded.push({
  1693. provider,
  1694. prefix,
  1695. name
  1696. });
  1697. } else if (storage2.missing.has(name)) {
  1698. icons.missing.push({
  1699. provider,
  1700. prefix,
  1701. name
  1702. });
  1703. } else {
  1704. hasPending = true;
  1705. return true;
  1706. }
  1707. return false;
  1708. });
  1709. if (icons.pending.length !== oldLength) {
  1710. if (!hasPending) {
  1711. removeCallback([storage2], item.id);
  1712. }
  1713. item.callback(
  1714. icons.loaded.slice(0),
  1715. icons.missing.slice(0),
  1716. icons.pending.slice(0),
  1717. item.abort
  1718. );
  1719. }
  1720. });
  1721. });
  1722. }
  1723. }
  1724. let idCounter = 0;
  1725. function storeCallback(callback, icons, pendingSources) {
  1726. const id = idCounter++;
  1727. const abort = removeCallback.bind(null, pendingSources, id);
  1728. if (!icons.pending.length) {
  1729. return abort;
  1730. }
  1731. const item = {
  1732. id,
  1733. icons,
  1734. callback,
  1735. abort
  1736. };
  1737. pendingSources.forEach((storage2) => {
  1738. (storage2.loaderCallbacks || (storage2.loaderCallbacks = [])).push(item);
  1739. });
  1740. return abort;
  1741. }
  1742. function listToIcons(list, validate = true, simpleNames2 = false) {
  1743. const result = [];
  1744. list.forEach((item) => {
  1745. const icon = typeof item === "string" ? stringToIcon(item, validate, simpleNames2) : item;
  1746. if (icon) {
  1747. result.push(icon);
  1748. }
  1749. });
  1750. return result;
  1751. }
  1752. var defaultConfig = {
  1753. resources: [],
  1754. index: 0,
  1755. timeout: 2e3,
  1756. rotate: 750,
  1757. random: false,
  1758. dataAfterTimeout: false
  1759. };
  1760. function sendQuery(config2, payload, query, done) {
  1761. const resourcesCount = config2.resources.length;
  1762. const startIndex = config2.random ? Math.floor(Math.random() * resourcesCount) : config2.index;
  1763. let resources;
  1764. if (config2.random) {
  1765. let list = config2.resources.slice(0);
  1766. resources = [];
  1767. while (list.length > 1) {
  1768. const nextIndex = Math.floor(Math.random() * list.length);
  1769. resources.push(list[nextIndex]);
  1770. list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1));
  1771. }
  1772. resources = resources.concat(list);
  1773. } else {
  1774. resources = config2.resources.slice(startIndex).concat(config2.resources.slice(0, startIndex));
  1775. }
  1776. const startTime = Date.now();
  1777. let status = "pending";
  1778. let queriesSent = 0;
  1779. let lastError;
  1780. let timer = null;
  1781. let queue = [];
  1782. let doneCallbacks = [];
  1783. if (typeof done === "function") {
  1784. doneCallbacks.push(done);
  1785. }
  1786. function resetTimer() {
  1787. if (timer) {
  1788. clearTimeout(timer);
  1789. timer = null;
  1790. }
  1791. }
  1792. function abort() {
  1793. if (status === "pending") {
  1794. status = "aborted";
  1795. }
  1796. resetTimer();
  1797. queue.forEach((item) => {
  1798. if (item.status === "pending") {
  1799. item.status = "aborted";
  1800. }
  1801. });
  1802. queue = [];
  1803. }
  1804. function subscribe(callback, overwrite) {
  1805. if (overwrite) {
  1806. doneCallbacks = [];
  1807. }
  1808. if (typeof callback === "function") {
  1809. doneCallbacks.push(callback);
  1810. }
  1811. }
  1812. function getQueryStatus() {
  1813. return {
  1814. startTime,
  1815. payload,
  1816. status,
  1817. queriesSent,
  1818. queriesPending: queue.length,
  1819. subscribe,
  1820. abort
  1821. };
  1822. }
  1823. function failQuery() {
  1824. status = "failed";
  1825. doneCallbacks.forEach((callback) => {
  1826. callback(void 0, lastError);
  1827. });
  1828. }
  1829. function clearQueue() {
  1830. queue.forEach((item) => {
  1831. if (item.status === "pending") {
  1832. item.status = "aborted";
  1833. }
  1834. });
  1835. queue = [];
  1836. }
  1837. function moduleResponse(item, response, data) {
  1838. const isError = response !== "success";
  1839. queue = queue.filter((queued) => queued !== item);
  1840. switch (status) {
  1841. case "pending":
  1842. break;
  1843. case "failed":
  1844. if (isError || !config2.dataAfterTimeout) {
  1845. return;
  1846. }
  1847. break;
  1848. default:
  1849. return;
  1850. }
  1851. if (response === "abort") {
  1852. lastError = data;
  1853. failQuery();
  1854. return;
  1855. }
  1856. if (isError) {
  1857. lastError = data;
  1858. if (!queue.length) {
  1859. if (!resources.length) {
  1860. failQuery();
  1861. } else {
  1862. execNext();
  1863. }
  1864. }
  1865. return;
  1866. }
  1867. resetTimer();
  1868. clearQueue();
  1869. if (!config2.random) {
  1870. const index = config2.resources.indexOf(item.resource);
  1871. if (index !== -1 && index !== config2.index) {
  1872. config2.index = index;
  1873. }
  1874. }
  1875. status = "completed";
  1876. doneCallbacks.forEach((callback) => {
  1877. callback(data);
  1878. });
  1879. }
  1880. function execNext() {
  1881. if (status !== "pending") {
  1882. return;
  1883. }
  1884. resetTimer();
  1885. const resource = resources.shift();
  1886. if (resource === void 0) {
  1887. if (queue.length) {
  1888. timer = setTimeout(() => {
  1889. resetTimer();
  1890. if (status === "pending") {
  1891. clearQueue();
  1892. failQuery();
  1893. }
  1894. }, config2.timeout);
  1895. return;
  1896. }
  1897. failQuery();
  1898. return;
  1899. }
  1900. const item = {
  1901. status: "pending",
  1902. resource,
  1903. callback: (status2, data) => {
  1904. moduleResponse(item, status2, data);
  1905. }
  1906. };
  1907. queue.push(item);
  1908. queriesSent++;
  1909. timer = setTimeout(execNext, config2.rotate);
  1910. query(resource, payload, item.callback);
  1911. }
  1912. setTimeout(execNext);
  1913. return getQueryStatus;
  1914. }
  1915. function initRedundancy(cfg) {
  1916. const config2 = {
  1917. ...defaultConfig,
  1918. ...cfg
  1919. };
  1920. let queries = [];
  1921. function cleanup() {
  1922. queries = queries.filter((item) => item().status === "pending");
  1923. }
  1924. function query(payload, queryCallback, doneCallback) {
  1925. const query2 = sendQuery(
  1926. config2,
  1927. payload,
  1928. queryCallback,
  1929. (data, error) => {
  1930. cleanup();
  1931. if (doneCallback) {
  1932. doneCallback(data, error);
  1933. }
  1934. }
  1935. );
  1936. queries.push(query2);
  1937. return query2;
  1938. }
  1939. function find(callback) {
  1940. return queries.find((value) => {
  1941. return callback(value);
  1942. }) || null;
  1943. }
  1944. const instance = {
  1945. query,
  1946. find,
  1947. setIndex: (index) => {
  1948. config2.index = index;
  1949. },
  1950. getIndex: () => config2.index,
  1951. cleanup
  1952. };
  1953. return instance;
  1954. }
  1955. function emptyCallback$1() {
  1956. }
  1957. const redundancyCache = /* @__PURE__ */ Object.create(null);
  1958. function getRedundancyCache(provider) {
  1959. if (!redundancyCache[provider]) {
  1960. const config2 = getAPIConfig(provider);
  1961. if (!config2) {
  1962. return;
  1963. }
  1964. const redundancy = initRedundancy(config2);
  1965. const cachedReundancy = {
  1966. config: config2,
  1967. redundancy
  1968. };
  1969. redundancyCache[provider] = cachedReundancy;
  1970. }
  1971. return redundancyCache[provider];
  1972. }
  1973. function sendAPIQuery(target, query, callback) {
  1974. let redundancy;
  1975. let send2;
  1976. if (typeof target === "string") {
  1977. const api = getAPIModule(target);
  1978. if (!api) {
  1979. callback(void 0, 424);
  1980. return emptyCallback$1;
  1981. }
  1982. send2 = api.send;
  1983. const cached = getRedundancyCache(target);
  1984. if (cached) {
  1985. redundancy = cached.redundancy;
  1986. }
  1987. } else {
  1988. const config2 = createAPIConfig(target);
  1989. if (config2) {
  1990. redundancy = initRedundancy(config2);
  1991. const moduleKey = target.resources ? target.resources[0] : "";
  1992. const api = getAPIModule(moduleKey);
  1993. if (api) {
  1994. send2 = api.send;
  1995. }
  1996. }
  1997. }
  1998. if (!redundancy || !send2) {
  1999. callback(void 0, 424);
  2000. return emptyCallback$1;
  2001. }
  2002. return redundancy.query(query, send2, callback)().abort;
  2003. }
  2004. const browserCacheVersion = "iconify2";
  2005. const browserCachePrefix = "iconify";
  2006. const browserCacheCountKey = browserCachePrefix + "-count";
  2007. const browserCacheVersionKey = browserCachePrefix + "-version";
  2008. const browserStorageHour = 36e5;
  2009. const browserStorageCacheExpiration = 168;
  2010. function getStoredItem(func, key) {
  2011. try {
  2012. return func.getItem(key);
  2013. } catch (err) {
  2014. }
  2015. }
  2016. function setStoredItem(func, key, value) {
  2017. try {
  2018. func.setItem(key, value);
  2019. return true;
  2020. } catch (err) {
  2021. }
  2022. }
  2023. function removeStoredItem(func, key) {
  2024. try {
  2025. func.removeItem(key);
  2026. } catch (err) {
  2027. }
  2028. }
  2029. function setBrowserStorageItemsCount(storage2, value) {
  2030. return setStoredItem(storage2, browserCacheCountKey, value.toString());
  2031. }
  2032. function getBrowserStorageItemsCount(storage2) {
  2033. return parseInt(getStoredItem(storage2, browserCacheCountKey)) || 0;
  2034. }
  2035. const browserStorageConfig = {
  2036. local: true,
  2037. session: true
  2038. };
  2039. const browserStorageEmptyItems = {
  2040. local: /* @__PURE__ */ new Set(),
  2041. session: /* @__PURE__ */ new Set()
  2042. };
  2043. let browserStorageStatus = false;
  2044. function setBrowserStorageStatus(status) {
  2045. browserStorageStatus = status;
  2046. }
  2047. let _window = typeof window === "undefined" ? {} : window;
  2048. function getBrowserStorage(key) {
  2049. const attr = key + "Storage";
  2050. try {
  2051. if (_window && _window[attr] && typeof _window[attr].length === "number") {
  2052. return _window[attr];
  2053. }
  2054. } catch (err) {
  2055. }
  2056. browserStorageConfig[key] = false;
  2057. }
  2058. function iterateBrowserStorage(key, callback) {
  2059. const func = getBrowserStorage(key);
  2060. if (!func) {
  2061. return;
  2062. }
  2063. const version = getStoredItem(func, browserCacheVersionKey);
  2064. if (version !== browserCacheVersion) {
  2065. if (version) {
  2066. const total2 = getBrowserStorageItemsCount(func);
  2067. for (let i = 0; i < total2; i++) {
  2068. removeStoredItem(func, browserCachePrefix + i.toString());
  2069. }
  2070. }
  2071. setStoredItem(func, browserCacheVersionKey, browserCacheVersion);
  2072. setBrowserStorageItemsCount(func, 0);
  2073. return;
  2074. }
  2075. const minTime = Math.floor(Date.now() / browserStorageHour) - browserStorageCacheExpiration;
  2076. const parseItem = (index) => {
  2077. const name = browserCachePrefix + index.toString();
  2078. const item = getStoredItem(func, name);
  2079. if (typeof item !== "string") {
  2080. return;
  2081. }
  2082. try {
  2083. const data = JSON.parse(item);
  2084. if (typeof data === "object" && typeof data.cached === "number" && data.cached > minTime && typeof data.provider === "string" && typeof data.data === "object" && typeof data.data.prefix === "string" && // Valid item: run callback
  2085. callback(data, index)) {
  2086. return true;
  2087. }
  2088. } catch (err) {
  2089. }
  2090. removeStoredItem(func, name);
  2091. };
  2092. let total = getBrowserStorageItemsCount(func);
  2093. for (let i = total - 1; i >= 0; i--) {
  2094. if (!parseItem(i)) {
  2095. if (i === total - 1) {
  2096. total--;
  2097. setBrowserStorageItemsCount(func, total);
  2098. } else {
  2099. browserStorageEmptyItems[key].add(i);
  2100. }
  2101. }
  2102. }
  2103. }
  2104. function initBrowserStorage() {
  2105. if (browserStorageStatus) {
  2106. return;
  2107. }
  2108. setBrowserStorageStatus(true);
  2109. for (const key in browserStorageConfig) {
  2110. iterateBrowserStorage(key, (item) => {
  2111. const iconSet = item.data;
  2112. const provider = item.provider;
  2113. const prefix = iconSet.prefix;
  2114. const storage2 = getStorage(
  2115. provider,
  2116. prefix
  2117. );
  2118. if (!addIconSet(storage2, iconSet).length) {
  2119. return false;
  2120. }
  2121. const lastModified = iconSet.lastModified || -1;
  2122. storage2.lastModifiedCached = storage2.lastModifiedCached ? Math.min(storage2.lastModifiedCached, lastModified) : lastModified;
  2123. return true;
  2124. });
  2125. }
  2126. }
  2127. function updateLastModified(storage2, lastModified) {
  2128. const lastValue = storage2.lastModifiedCached;
  2129. if (
  2130. // Matches or newer
  2131. lastValue && lastValue >= lastModified
  2132. ) {
  2133. return lastValue === lastModified;
  2134. }
  2135. storage2.lastModifiedCached = lastModified;
  2136. if (lastValue) {
  2137. for (const key in browserStorageConfig) {
  2138. iterateBrowserStorage(key, (item) => {
  2139. const iconSet = item.data;
  2140. return item.provider !== storage2.provider || iconSet.prefix !== storage2.prefix || iconSet.lastModified === lastModified;
  2141. });
  2142. }
  2143. }
  2144. return true;
  2145. }
  2146. function storeInBrowserStorage(storage2, data) {
  2147. if (!browserStorageStatus) {
  2148. initBrowserStorage();
  2149. }
  2150. function store(key) {
  2151. let func;
  2152. if (!browserStorageConfig[key] || !(func = getBrowserStorage(key))) {
  2153. return;
  2154. }
  2155. const set = browserStorageEmptyItems[key];
  2156. let index;
  2157. if (set.size) {
  2158. set.delete(index = Array.from(set).shift());
  2159. } else {
  2160. index = getBrowserStorageItemsCount(func);
  2161. if (!setBrowserStorageItemsCount(func, index + 1)) {
  2162. return;
  2163. }
  2164. }
  2165. const item = {
  2166. cached: Math.floor(Date.now() / browserStorageHour),
  2167. provider: storage2.provider,
  2168. data
  2169. };
  2170. return setStoredItem(
  2171. func,
  2172. browserCachePrefix + index.toString(),
  2173. JSON.stringify(item)
  2174. );
  2175. }
  2176. if (data.lastModified && !updateLastModified(storage2, data.lastModified)) {
  2177. return;
  2178. }
  2179. if (!Object.keys(data.icons).length) {
  2180. return;
  2181. }
  2182. if (data.not_found) {
  2183. data = Object.assign({}, data);
  2184. delete data.not_found;
  2185. }
  2186. if (!store("local")) {
  2187. store("session");
  2188. }
  2189. }
  2190. function emptyCallback() {
  2191. }
  2192. function loadedNewIcons(storage2) {
  2193. if (!storage2.iconsLoaderFlag) {
  2194. storage2.iconsLoaderFlag = true;
  2195. setTimeout(() => {
  2196. storage2.iconsLoaderFlag = false;
  2197. updateCallbacks(storage2);
  2198. });
  2199. }
  2200. }
  2201. function loadNewIcons(storage2, icons) {
  2202. if (!storage2.iconsToLoad) {
  2203. storage2.iconsToLoad = icons;
  2204. } else {
  2205. storage2.iconsToLoad = storage2.iconsToLoad.concat(icons).sort();
  2206. }
  2207. if (!storage2.iconsQueueFlag) {
  2208. storage2.iconsQueueFlag = true;
  2209. setTimeout(() => {
  2210. storage2.iconsQueueFlag = false;
  2211. const { provider, prefix } = storage2;
  2212. const icons2 = storage2.iconsToLoad;
  2213. delete storage2.iconsToLoad;
  2214. let api;
  2215. if (!icons2 || !(api = getAPIModule(provider))) {
  2216. return;
  2217. }
  2218. const params = api.prepare(provider, prefix, icons2);
  2219. params.forEach((item) => {
  2220. sendAPIQuery(provider, item, (data) => {
  2221. if (typeof data !== "object") {
  2222. item.icons.forEach((name) => {
  2223. storage2.missing.add(name);
  2224. });
  2225. } else {
  2226. try {
  2227. const parsed = addIconSet(
  2228. storage2,
  2229. data
  2230. );
  2231. if (!parsed.length) {
  2232. return;
  2233. }
  2234. const pending = storage2.pendingIcons;
  2235. if (pending) {
  2236. parsed.forEach((name) => {
  2237. pending.delete(name);
  2238. });
  2239. }
  2240. storeInBrowserStorage(storage2, data);
  2241. } catch (err) {
  2242. console.error(err);
  2243. }
  2244. }
  2245. loadedNewIcons(storage2);
  2246. });
  2247. });
  2248. });
  2249. }
  2250. }
  2251. const loadIcons = (icons, callback) => {
  2252. const cleanedIcons = listToIcons(icons, true, allowSimpleNames());
  2253. const sortedIcons = sortIcons(cleanedIcons);
  2254. if (!sortedIcons.pending.length) {
  2255. let callCallback = true;
  2256. if (callback) {
  2257. setTimeout(() => {
  2258. if (callCallback) {
  2259. callback(
  2260. sortedIcons.loaded,
  2261. sortedIcons.missing,
  2262. sortedIcons.pending,
  2263. emptyCallback
  2264. );
  2265. }
  2266. });
  2267. }
  2268. return () => {
  2269. callCallback = false;
  2270. };
  2271. }
  2272. const newIcons = /* @__PURE__ */ Object.create(null);
  2273. const sources = [];
  2274. let lastProvider, lastPrefix;
  2275. sortedIcons.pending.forEach((icon) => {
  2276. const { provider, prefix } = icon;
  2277. if (prefix === lastPrefix && provider === lastProvider) {
  2278. return;
  2279. }
  2280. lastProvider = provider;
  2281. lastPrefix = prefix;
  2282. sources.push(getStorage(provider, prefix));
  2283. const providerNewIcons = newIcons[provider] || (newIcons[provider] = /* @__PURE__ */ Object.create(null));
  2284. if (!providerNewIcons[prefix]) {
  2285. providerNewIcons[prefix] = [];
  2286. }
  2287. });
  2288. sortedIcons.pending.forEach((icon) => {
  2289. const { provider, prefix, name } = icon;
  2290. const storage2 = getStorage(provider, prefix);
  2291. const pendingQueue = storage2.pendingIcons || (storage2.pendingIcons = /* @__PURE__ */ new Set());
  2292. if (!pendingQueue.has(name)) {
  2293. pendingQueue.add(name);
  2294. newIcons[provider][prefix].push(name);
  2295. }
  2296. });
  2297. sources.forEach((storage2) => {
  2298. const { provider, prefix } = storage2;
  2299. if (newIcons[provider][prefix].length) {
  2300. loadNewIcons(storage2, newIcons[provider][prefix]);
  2301. }
  2302. });
  2303. return callback ? storeCallback(callback, sortedIcons, sources) : emptyCallback;
  2304. };
  2305. function mergeCustomisations(defaults, item) {
  2306. const result = {
  2307. ...defaults
  2308. };
  2309. for (const key in item) {
  2310. const value = item[key];
  2311. const valueType = typeof value;
  2312. if (key in defaultIconSizeCustomisations) {
  2313. if (value === null || value && (valueType === "string" || valueType === "number")) {
  2314. result[key] = value;
  2315. }
  2316. } else if (valueType === typeof result[key]) {
  2317. result[key] = key === "rotate" ? value % 4 : value;
  2318. }
  2319. }
  2320. return result;
  2321. }
  2322. const separator = /[\s,]+/;
  2323. function flipFromString(custom, flip) {
  2324. flip.split(separator).forEach((str) => {
  2325. const value = str.trim();
  2326. switch (value) {
  2327. case "horizontal":
  2328. custom.hFlip = true;
  2329. break;
  2330. case "vertical":
  2331. custom.vFlip = true;
  2332. break;
  2333. }
  2334. });
  2335. }
  2336. function rotateFromString(value, defaultValue = 0) {
  2337. const units = value.replace(/^-?[0-9.]*/, "");
  2338. function cleanup(value2) {
  2339. while (value2 < 0) {
  2340. value2 += 4;
  2341. }
  2342. return value2 % 4;
  2343. }
  2344. if (units === "") {
  2345. const num = parseInt(value);
  2346. return isNaN(num) ? 0 : cleanup(num);
  2347. } else if (units !== value) {
  2348. let split = 0;
  2349. switch (units) {
  2350. case "%":
  2351. split = 25;
  2352. break;
  2353. case "deg":
  2354. split = 90;
  2355. }
  2356. if (split) {
  2357. let num = parseFloat(value.slice(0, value.length - units.length));
  2358. if (isNaN(num)) {
  2359. return 0;
  2360. }
  2361. num = num / split;
  2362. return num % 1 === 0 ? cleanup(num) : 0;
  2363. }
  2364. }
  2365. return defaultValue;
  2366. }
  2367. function iconToHTML(body, attributes) {
  2368. let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : ' xmlns:xlink="http://www.w3.org/1999/xlink"';
  2369. for (const attr in attributes) {
  2370. renderAttribsHTML += " " + attr + '="' + attributes[attr] + '"';
  2371. }
  2372. return '<svg xmlns="http://www.w3.org/2000/svg"' + renderAttribsHTML + ">" + body + "</svg>";
  2373. }
  2374. function encodeSVGforURL(svg) {
  2375. return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ");
  2376. }
  2377. function svgToData(svg) {
  2378. return "data:image/svg+xml," + encodeSVGforURL(svg);
  2379. }
  2380. function svgToURL(svg) {
  2381. return 'url("' + svgToData(svg) + '")';
  2382. }
  2383. const defaultExtendedIconCustomisations = {
  2384. ...defaultIconCustomisations,
  2385. inline: false
  2386. };
  2387. const svgDefaults = {
  2388. "xmlns": "http://www.w3.org/2000/svg",
  2389. "xmlns:xlink": "http://www.w3.org/1999/xlink",
  2390. "aria-hidden": true,
  2391. "role": "img"
  2392. };
  2393. const commonProps = {
  2394. display: "inline-block"
  2395. };
  2396. const monotoneProps = {
  2397. backgroundColor: "currentColor"
  2398. };
  2399. const coloredProps = {
  2400. backgroundColor: "transparent"
  2401. };
  2402. const propsToAdd = {
  2403. Image: "var(--svg)",
  2404. Repeat: "no-repeat",
  2405. Size: "100% 100%"
  2406. };
  2407. const propsToAddTo = {
  2408. webkitMask: monotoneProps,
  2409. mask: monotoneProps,
  2410. background: coloredProps
  2411. };
  2412. for (const prefix in propsToAddTo) {
  2413. const list = propsToAddTo[prefix];
  2414. for (const prop in propsToAdd) {
  2415. list[prefix + prop] = propsToAdd[prop];
  2416. }
  2417. }
  2418. const customisationAliases = {};
  2419. ["horizontal", "vertical"].forEach((prefix) => {
  2420. const attr = prefix.slice(0, 1) + "Flip";
  2421. customisationAliases[prefix + "-flip"] = attr;
  2422. customisationAliases[prefix.slice(0, 1) + "-flip"] = attr;
  2423. customisationAliases[prefix + "Flip"] = attr;
  2424. });
  2425. function fixSize(value) {
  2426. return value + (value.match(/^[-0-9.]+$/) ? "px" : "");
  2427. }
  2428. const render = (icon, props) => {
  2429. const customisations = mergeCustomisations(defaultExtendedIconCustomisations, props);
  2430. const componentProps = { ...svgDefaults };
  2431. const mode = props.mode || "svg";
  2432. const style = {};
  2433. const propsStyle = props.style;
  2434. const customStyle = typeof propsStyle === "object" && !(propsStyle instanceof Array) ? propsStyle : {};
  2435. for (let key in props) {
  2436. const value = props[key];
  2437. if (value === void 0) {
  2438. continue;
  2439. }
  2440. switch (key) {
  2441. case "icon":
  2442. case "style":
  2443. case "onLoad":
  2444. case "mode":
  2445. break;
  2446. case "inline":
  2447. case "hFlip":
  2448. case "vFlip":
  2449. customisations[key] = value === true || value === "true" || value === 1;
  2450. break;
  2451. case "flip":
  2452. if (typeof value === "string") {
  2453. flipFromString(customisations, value);
  2454. }
  2455. break;
  2456. case "color":
  2457. style.color = value;
  2458. break;
  2459. case "rotate":
  2460. if (typeof value === "string") {
  2461. customisations[key] = rotateFromString(value);
  2462. } else if (typeof value === "number") {
  2463. customisations[key] = value;
  2464. }
  2465. break;
  2466. case "ariaHidden":
  2467. case "aria-hidden":
  2468. if (value !== true && value !== "true") {
  2469. delete componentProps["aria-hidden"];
  2470. }
  2471. break;
  2472. default: {
  2473. const alias = customisationAliases[key];
  2474. if (alias) {
  2475. if (value === true || value === "true" || value === 1) {
  2476. customisations[alias] = true;
  2477. }
  2478. } else if (defaultExtendedIconCustomisations[key] === void 0) {
  2479. componentProps[key] = value;
  2480. }
  2481. }
  2482. }
  2483. }
  2484. const item = iconToSVG(icon, customisations);
  2485. const renderAttribs = item.attributes;
  2486. if (customisations.inline) {
  2487. style.verticalAlign = "-0.125em";
  2488. }
  2489. if (mode === "svg") {
  2490. componentProps.style = {
  2491. ...style,
  2492. ...customStyle
  2493. };
  2494. Object.assign(componentProps, renderAttribs);
  2495. let localCounter = 0;
  2496. let id = props.id;
  2497. if (typeof id === "string") {
  2498. id = id.replace(/-/g, "_");
  2499. }
  2500. componentProps["innerHTML"] = replaceIDs(item.body, id ? () => id + "ID" + localCounter++ : "iconifyVue");
  2501. return vue.h("svg", componentProps);
  2502. }
  2503. const { body, width, height } = icon;
  2504. const useMask = mode === "mask" || (mode === "bg" ? false : body.indexOf("currentColor") !== -1);
  2505. const html = iconToHTML(body, {
  2506. ...renderAttribs,
  2507. width: width + "",
  2508. height: height + ""
  2509. });
  2510. componentProps.style = {
  2511. ...style,
  2512. "--svg": svgToURL(html),
  2513. "width": fixSize(renderAttribs.width),
  2514. "height": fixSize(renderAttribs.height),
  2515. ...commonProps,
  2516. ...useMask ? monotoneProps : coloredProps,
  2517. ...customStyle
  2518. };
  2519. return vue.h("span", componentProps);
  2520. };
  2521. allowSimpleNames(true);
  2522. setAPIModule("", fetchAPIModule);
  2523. if (typeof document !== "undefined" && typeof window !== "undefined") {
  2524. initBrowserStorage();
  2525. const _window2 = window;
  2526. if (_window2.IconifyPreload !== void 0) {
  2527. const preload = _window2.IconifyPreload;
  2528. const err = "Invalid IconifyPreload syntax.";
  2529. if (typeof preload === "object" && preload !== null) {
  2530. (preload instanceof Array ? preload : [preload]).forEach((item) => {
  2531. try {
  2532. if (
  2533. // Check if item is an object and not null/array
  2534. typeof item !== "object" || item === null || item instanceof Array || // Check for 'icons' and 'prefix'
  2535. typeof item.icons !== "object" || typeof item.prefix !== "string" || // Add icon set
  2536. !addCollection(item)
  2537. ) {
  2538. console.error(err);
  2539. }
  2540. } catch (e2) {
  2541. console.error(err);
  2542. }
  2543. });
  2544. }
  2545. }
  2546. if (_window2.IconifyProviders !== void 0) {
  2547. const providers = _window2.IconifyProviders;
  2548. if (typeof providers === "object" && providers !== null) {
  2549. for (let key in providers) {
  2550. const err = "IconifyProviders[" + key + "] is invalid.";
  2551. try {
  2552. const value = providers[key];
  2553. if (typeof value !== "object" || !value || value.resources === void 0) {
  2554. continue;
  2555. }
  2556. if (!addAPIProvider(key, value)) {
  2557. console.error(err);
  2558. }
  2559. } catch (e2) {
  2560. console.error(err);
  2561. }
  2562. }
  2563. }
  2564. }
  2565. }
  2566. const emptyIcon = {
  2567. ...defaultIconProps,
  2568. body: ""
  2569. };
  2570. const Icon = vue.defineComponent({
  2571. // Do not inherit other attributes: it is handled by render()
  2572. inheritAttrs: false,
  2573. // Set initial data
  2574. data() {
  2575. return {
  2576. // Mounted status
  2577. iconMounted: false,
  2578. // Callback counter to trigger re-render
  2579. counter: 0
  2580. };
  2581. },
  2582. mounted() {
  2583. this._name = "";
  2584. this._loadingIcon = null;
  2585. this.iconMounted = true;
  2586. },
  2587. unmounted() {
  2588. this.abortLoading();
  2589. },
  2590. methods: {
  2591. abortLoading() {
  2592. if (this._loadingIcon) {
  2593. this._loadingIcon.abort();
  2594. this._loadingIcon = null;
  2595. }
  2596. },
  2597. // Get data for icon to render or null
  2598. getIcon(icon, onload) {
  2599. if (typeof icon === "object" && icon !== null && typeof icon.body === "string") {
  2600. this._name = "";
  2601. this.abortLoading();
  2602. return {
  2603. data: icon
  2604. };
  2605. }
  2606. let iconName;
  2607. if (typeof icon !== "string" || (iconName = stringToIcon(icon, false, true)) === null) {
  2608. this.abortLoading();
  2609. return null;
  2610. }
  2611. const data = getIconData(iconName);
  2612. if (!data) {
  2613. if (!this._loadingIcon || this._loadingIcon.name !== icon) {
  2614. this.abortLoading();
  2615. this._name = "";
  2616. if (data !== null) {
  2617. this._loadingIcon = {
  2618. name: icon,
  2619. abort: loadIcons([iconName], () => {
  2620. this.counter++;
  2621. })
  2622. };
  2623. }
  2624. }
  2625. return null;
  2626. }
  2627. this.abortLoading();
  2628. if (this._name !== icon) {
  2629. this._name = icon;
  2630. if (onload) {
  2631. onload(icon);
  2632. }
  2633. }
  2634. const classes = ["iconify"];
  2635. if (iconName.prefix !== "") {
  2636. classes.push("iconify--" + iconName.prefix);
  2637. }
  2638. if (iconName.provider !== "") {
  2639. classes.push("iconify--" + iconName.provider);
  2640. }
  2641. return { data, classes };
  2642. }
  2643. },
  2644. // Render icon
  2645. render() {
  2646. this.counter;
  2647. const props = this.$attrs;
  2648. const icon = this.iconMounted ? this.getIcon(props.icon, props.onLoad) : null;
  2649. if (!icon) {
  2650. return render(emptyIcon, props);
  2651. }
  2652. let newProps = props;
  2653. if (icon.classes) {
  2654. newProps = {
  2655. ...props,
  2656. class: (typeof props["class"] === "string" ? props["class"] + " " : "") + icon.classes.join(" ")
  2657. };
  2658. }
  2659. return render({
  2660. ...defaultIconProps,
  2661. ...icon.data
  2662. }, newProps);
  2663. }
  2664. });
  2665. const _hoisted_1$i = { class: "display-type" };
  2666. const _hoisted_2$f = { style: { "position": "relative" } };
  2667. const _hoisted_3$c = {
  2668. key: 0,
  2669. class: "type-list"
  2670. };
  2671. const _sfc_main$k = /* @__PURE__ */ vue.defineComponent({
  2672. __name: "BaseSelect",
  2673. props: {
  2674. displayType: {}
  2675. },
  2676. emits: ["update:displayType"],
  2677. setup(__props, { emit: __emit }) {
  2678. const props = __props;
  2679. const emit = __emit;
  2680. let state = vue.reactive({
  2681. showChangeDisplayType: false,
  2682. lastDisplayType: null
  2683. });
  2684. function changeOption(item) {
  2685. if (![CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2686. state.lastDisplayType = props.displayType;
  2687. }
  2688. emit("update:displayType", item);
  2689. state.showChangeDisplayType = false;
  2690. }
  2691. function clickDisplayType() {
  2692. if ([CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2693. return changeOption(state.lastDisplayType ?? CommentDisplayType.FloorInFloorNoCallUser);
  2694. }
  2695. state.showChangeDisplayType = !state.showChangeDisplayType;
  2696. }
  2697. const currentDisplayType = vue.computed(() => {
  2698. let judge = props.displayType;
  2699. if ([CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2700. judge = state.lastDisplayType;
  2701. }
  2702. switch (judge) {
  2703. case CommentDisplayType.FloorInFloorNoCallUser:
  2704. return "楼中楼";
  2705. case CommentDisplayType.FloorInFloor:
  2706. return "楼中楼(@)";
  2707. case CommentDisplayType.FloorInFloorNested:
  2708. return "冗余楼中楼";
  2709. case CommentDisplayType.V2exOrigin:
  2710. return "V2原版";
  2711. case CommentDisplayType.OnlyOp:
  2712. return "只看楼主";
  2713. default:
  2714. return "楼中楼";
  2715. }
  2716. });
  2717. return (_ctx, _cache) => {
  2718. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$i, [
  2719. vue.createElementVNode("div", {
  2720. class: vue.normalizeClass(["type", _ctx.displayType === vue.unref(CommentDisplayType).New && "active"]),
  2721. onClick: _cache[0] || (_cache[0] = ($event) => changeOption(vue.unref(CommentDisplayType).New))
  2722. }, "最新 ", 2),
  2723. vue.createElementVNode("div", {
  2724. class: vue.normalizeClass(["type", _ctx.displayType === vue.unref(CommentDisplayType).Like && "active"]),
  2725. onClick: _cache[1] || (_cache[1] = ($event) => changeOption(vue.unref(CommentDisplayType).Like))
  2726. }, "最热 ", 2),
  2727. vue.createElementVNode("div", _hoisted_2$f, [
  2728. vue.createElementVNode("div", {
  2729. class: vue.normalizeClass(["type", ![vue.unref(CommentDisplayType).New, vue.unref(CommentDisplayType).Like].includes(_ctx.displayType) && "active"]),
  2730. onClick: clickDisplayType
  2731. }, [
  2732. vue.createElementVNode("span", null, vue.toDisplayString(currentDisplayType.value), 1),
  2733. vue.createVNode(vue.unref(Icon), { icon: "mingcute:down-line" })
  2734. ], 2),
  2735. vue.unref(state).showChangeDisplayType ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$c, [
  2736. vue.createElementVNode("div", {
  2737. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloorNoCallUser && "active"]),
  2738. onClick: _cache[2] || (_cache[2] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloorNoCallUser), ["stop"]))
  2739. }, "楼中楼 ", 2),
  2740. vue.createElementVNode("div", {
  2741. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloor && "active"]),
  2742. onClick: _cache[3] || (_cache[3] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloor), ["stop"]))
  2743. }, "楼中楼(@) ", 2),
  2744. vue.createElementVNode("div", {
  2745. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloorNested && "active"]),
  2746. onClick: _cache[4] || (_cache[4] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloorNested), ["stop"]))
  2747. }, "冗余楼中楼 ", 2),
  2748. vue.createElementVNode("div", {
  2749. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).OnlyOp && "active"]),
  2750. onClick: _cache[5] || (_cache[5] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).OnlyOp), ["stop"]))
  2751. }, "只看楼主 ", 2),
  2752. vue.createElementVNode("div", {
  2753. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).V2exOrigin && "active"]),
  2754. onClick: _cache[6] || (_cache[6] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).V2exOrigin), ["stop"]))
  2755. }, "V2原版 ", 2)
  2756. ])) : vue.createCommentVNode("", true)
  2757. ])
  2758. ]);
  2759. };
  2760. }
  2761. });
  2762. const BaseSelect = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-e4f684be"]]);
  2763. const eventBus = {
  2764. eventMap: /* @__PURE__ */ new Map(),
  2765. on(eventType, cb) {
  2766. let cbs = this.eventMap.get(eventType);
  2767. if (cbs) {
  2768. cbs.push(cb);
  2769. } else {
  2770. cbs = [cb];
  2771. }
  2772. this.eventMap.set(eventType, cbs);
  2773. },
  2774. offOne(eventType, cb) {
  2775. let cbs = this.eventMap.get(eventType);
  2776. if (cbs) {
  2777. let rIndex = cbs.findIndex((c) => c === cb);
  2778. if (rIndex > -1) {
  2779. cbs.splice(rIndex, 1);
  2780. }
  2781. }
  2782. this.eventMap.set(eventType, cbs);
  2783. },
  2784. emit(eventType, val) {
  2785. let cbs = this.eventMap.get(eventType);
  2786. if (cbs) {
  2787. cbs.map((cb) => cb(val));
  2788. }
  2789. },
  2790. off(eventType) {
  2791. let cbs = this.eventMap.has(eventType);
  2792. if (cbs) {
  2793. this.eventMap.delete(eventType);
  2794. }
  2795. },
  2796. clear() {
  2797. this.eventMap = /* @__PURE__ */ new Map();
  2798. }
  2799. };
  2800. const CMD = {
  2801. SHOW_TOOLTIP: "SHOW_TOOLTIP",
  2802. SHOW_MSG: "SHOW_MSG",
  2803. SET_CALL: "SET_CALL",
  2804. SHOW_CALL: "SHOW_CALL",
  2805. REFRESH_ONCE: "REFRESH_ONCE",
  2806. ADD_REPLY: "ADD_REPLY",
  2807. IGNORE: "IGNORE",
  2808. MERGE: "MERGE",
  2809. REMOVE: "REMOVE",
  2810. CHANGE_COMMENT_THANK: "CHANGE_COMMENT_THANK",
  2811. CHANGE_POST_THANK: "CHANGE_POST_THANK",
  2812. ADD_TAG: "ADD_TAG",
  2813. REMOVE_TAG: "REMOVE_TAG",
  2814. RELATION_REPLY: "RELATION_REPLY",
  2815. JUMP: "JUMP",
  2816. REFRESH_POST: "REFRESH_POST",
  2817. SHOW_CONFIRM_MODAL: "SHOW_CONFIRM_MODAL",
  2818. SHOW_CONFIRM_MODAL_CONFIRM: "SHOW_CONFIRM_MODAL_CONFIRM"
  2819. };
  2820. const _sfc_main$j = {
  2821. name: "PopConfirm",
  2822. props: {
  2823. title: {
  2824. type: String,
  2825. default() {
  2826. return "";
  2827. }
  2828. },
  2829. disabled: {
  2830. type: Boolean,
  2831. default() {
  2832. return false;
  2833. }
  2834. }
  2835. },
  2836. data() {
  2837. return {
  2838. id: ""
  2839. };
  2840. },
  2841. created() {
  2842. },
  2843. methods: {
  2844. cb(id) {
  2845. if (id === this.id) {
  2846. this.$emit("confirm");
  2847. this.id = "";
  2848. }
  2849. },
  2850. showPop(e2) {
  2851. if (this.disabled)
  2852. return;
  2853. let rect = e2.target.getBoundingClientRect();
  2854. this.id = Date.now();
  2855. eventBus.emit(CMD.SHOW_CONFIRM_MODAL, { title: this.title, rect, id: this.id });
  2856. eventBus.offOne(CMD.SHOW_CONFIRM_MODAL_CONFIRM, this.cb);
  2857. eventBus.on(CMD.SHOW_CONFIRM_MODAL_CONFIRM, this.cb);
  2858. }
  2859. },
  2860. unmounted() {
  2861. eventBus.offOne(CMD.SHOW_CONFIRM_MODAL_CONFIRM, this.cb);
  2862. }
  2863. };
  2864. function _sfc_render$a(_ctx, _cache, $props, $setup, $data, $options) {
  2865. return vue.openBlock(), vue.createElementBlock("span", {
  2866. onClick: _cache[0] || (_cache[0] = vue.withModifiers((...args) => $options.showPop && $options.showPop(...args), ["stop"]))
  2867. }, [
  2868. vue.renderSlot(_ctx.$slots, "default")
  2869. ]);
  2870. }
  2871. const PopConfirm = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["render", _sfc_render$a]]);
  2872. const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
  2873. __name: "BaseLoading",
  2874. props: {
  2875. size: { default: "normal" }
  2876. },
  2877. setup(__props) {
  2878. return (_ctx, _cache) => {
  2879. return vue.openBlock(), vue.createElementBlock("div", {
  2880. class: vue.normalizeClass(["loading", [_ctx.size]])
  2881. }, null, 2);
  2882. };
  2883. }
  2884. });
  2885. const BaseLoading = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-2697baa2"]]);
  2886. const _hoisted_1$h = {
  2887. key: 1,
  2888. class: "key-notice"
  2889. };
  2890. const _hoisted_2$e = { class: "key" };
  2891. const _sfc_main$h = /* @__PURE__ */ vue.defineComponent({
  2892. __name: "BaseButton",
  2893. props: {
  2894. keyboard: {},
  2895. active: { type: Boolean },
  2896. disabled: { type: Boolean },
  2897. loading: { type: Boolean },
  2898. size: { default: "normal" },
  2899. type: { default: "primary" }
  2900. },
  2901. emits: ["click"],
  2902. setup(__props) {
  2903. return (_ctx, _cache) => {
  2904. return vue.openBlock(), vue.createBlock(Tooltip, {
  2905. disabled: !_ctx.keyboard,
  2906. title: `快捷键: ${_ctx.keyboard}`
  2907. }, {
  2908. default: vue.withCtx(() => [
  2909. vue.createElementVNode("div", vue.mergeProps({ class: "base-button" }, _ctx.$attrs, {
  2910. onClick: _cache[0] || (_cache[0] = (e2) => !_ctx.disabled && !_ctx.loading && _ctx.$emit("click", e2)),
  2911. class: [
  2912. _ctx.active && "active",
  2913. _ctx.size,
  2914. _ctx.type,
  2915. (_ctx.disabled || _ctx.loading) && "disabled",
  2916. !_ctx.disabled && "hvr-grow"
  2917. ]
  2918. }), [
  2919. vue.createElementVNode("span", {
  2920. style: vue.normalizeStyle({ opacity: _ctx.loading ? 0 : 1 })
  2921. }, [
  2922. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  2923. ], 4),
  2924. _ctx.loading ? (vue.openBlock(), vue.createBlock(BaseLoading, {
  2925. key: 0,
  2926. size: "small"
  2927. })) : vue.createCommentVNode("", true),
  2928. _ctx.keyboard ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$h, [
  2929. vue.createElementVNode("span", _hoisted_2$e, vue.toDisplayString(_ctx.keyboard), 1)
  2930. ])) : vue.createCommentVNode("", true)
  2931. ], 16)
  2932. ]),
  2933. _: 3
  2934. }, 8, ["disabled", "title"]);
  2935. };
  2936. }
  2937. });
  2938. const BaseButton = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["__scopeId", "data-v-5a7d79ba"]]);
  2939. const _sfc_main$g = {
  2940. name: "Setting",
  2941. components: {
  2942. BaseButton,
  2943. PopConfirm,
  2944. Icon,
  2945. BaseSelect,
  2946. BaseSwitch,
  2947. Tooltip
  2948. },
  2949. inject: ["isNight"],
  2950. props: {
  2951. show: {
  2952. type: Boolean,
  2953. default() {
  2954. return false;
  2955. }
  2956. }
  2957. },
  2958. data() {
  2959. return {
  2960. tabIndex: 0
  2961. };
  2962. },
  2963. methods: {
  2964. confirm() {
  2965. this.close();
  2966. this.$emit("confirm");
  2967. },
  2968. close() {
  2969. this.$emit("update:show", false);
  2970. }
  2971. }
  2972. };
  2973. const _withScopeId$b = (n2) => (vue.pushScopeId("data-v-386b43d0"), n2 = n2(), vue.popScopeId(), n2);
  2974. const _hoisted_1$g = {
  2975. key: 0,
  2976. class: "setting-modal modal"
  2977. };
  2978. const _hoisted_2$d = { class: "modal-root" };
  2979. const _hoisted_3$b = { class: "modal-header" };
  2980. const _hoisted_4$b = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 使用需知 ", -1));
  2981. const _hoisted_5$9 = { class: "body" };
  2982. const _hoisted_6$9 = /* @__PURE__ */ _withScopeId$b(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "modal-content" }, [
  2983. /* @__PURE__ */ vue.createElementVNode("div", null, "开启此功能会带来以下影响"),
  2984. /* @__PURE__ */ vue.createElementVNode("div", null, "缺点"),
  2985. /* @__PURE__ */ vue.createElementVNode("div", { style: { "color": "red" } }, [
  2986. /* @__PURE__ */ vue.createElementVNode("div", null, "1、你的IP可能会被封禁"),
  2987. /* @__PURE__ */ vue.createElementVNode("div", null, "2、消耗更多流量,给服务器带来更大的负担"),
  2988. /* @__PURE__ */ vue.createElementVNode("div", null, "3、你的V站浏览进度条会变快")
  2989. ]),
  2990. /* @__PURE__ */ vue.createElementVNode("div", null, "优点"),
  2991. /* @__PURE__ */ vue.createElementVNode("div", null, "1、卡片模式,无需打开主题即可查看内容"),
  2992. /* @__PURE__ */ vue.createElementVNode("div", null, "2、打开主题时提前预览正文内容,无需等待加载"),
  2993. /* @__PURE__ */ vue.createElementVNode("div", null, "原理"),
  2994. /* @__PURE__ */ vue.createElementVNode("div", null, "1、解析列表所有主题ID,批量调用show.json接口,获取对应主题的正文"),
  2995. /* @__PURE__ */ vue.createElementVNode("div", null, "2、请求的主题数据会缓存到本地,不会重复请求,超过3天的数据会删除"),
  2996. /* @__PURE__ */ vue.createElementVNode("div", null, "3、前面4条会并发请求,4条以后的一秒请求一条")
  2997. ], -1));
  2998. const _hoisted_7$8 = { class: "btns" };
  2999. function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
  3000. const _component_Icon = vue.resolveComponent("Icon");
  3001. const _component_BaseButton = vue.resolveComponent("BaseButton");
  3002. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  3003. default: vue.withCtx(() => [
  3004. $props.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, [
  3005. vue.createElementVNode("div", {
  3006. class: "mask",
  3007. onClick: _cache[0] || (_cache[0] = (...args) => $options.close && $options.close(...args))
  3008. }),
  3009. vue.createElementVNode("div", _hoisted_2$d, [
  3010. vue.createElementVNode("div", _hoisted_3$b, [
  3011. _hoisted_4$b,
  3012. vue.createVNode(_component_Icon, {
  3013. icon: "ic:round-close",
  3014. onClick: $options.close
  3015. }, null, 8, ["onClick"])
  3016. ]),
  3017. vue.createElementVNode("div", _hoisted_5$9, [
  3018. _hoisted_6$9,
  3019. vue.createElementVNode("div", _hoisted_7$8, [
  3020. vue.createVNode(_component_BaseButton, {
  3021. type: "link",
  3022. onClick: $options.close
  3023. }, {
  3024. default: vue.withCtx(() => [
  3025. vue.createTextVNode("不同意")
  3026. ]),
  3027. _: 1
  3028. }, 8, ["onClick"]),
  3029. vue.createVNode(_component_BaseButton, { onClick: $options.confirm }, {
  3030. default: vue.withCtx(() => [
  3031. vue.createTextVNode("同意")
  3032. ]),
  3033. _: 1
  3034. }, 8, ["onClick"])
  3035. ])
  3036. ])
  3037. ])
  3038. ])) : vue.createCommentVNode("", true)
  3039. ]),
  3040. _: 1
  3041. });
  3042. }
  3043. const NoticeModal = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["render", _sfc_render$9], ["__scopeId", "data-v-386b43d0"]]);
  3044. const _sfc_main$f = {
  3045. name: "Setting",
  3046. components: {
  3047. BaseButton,
  3048. NoticeModal,
  3049. PopConfirm,
  3050. Icon,
  3051. BaseSelect,
  3052. BaseSwitch,
  3053. Tooltip
  3054. },
  3055. inject: ["isNight", "isLogin"],
  3056. props: {
  3057. modelValue: {
  3058. type: Object,
  3059. default() {
  3060. return {};
  3061. }
  3062. },
  3063. show: {
  3064. type: Boolean,
  3065. default() {
  3066. return false;
  3067. }
  3068. }
  3069. },
  3070. data() {
  3071. return {
  3072. tabIndex: 0,
  3073. config: functions.clone(this.modelValue),
  3074. showNotice: false,
  3075. exportLoading: false,
  3076. importLoading: false,
  3077. importOk: false,
  3078. showInput: true,
  3079. total: 0,
  3080. index: 0,
  3081. endTime: "0"
  3082. };
  3083. },
  3084. computed: {
  3085. DefaultVal() {
  3086. return DefaultVal;
  3087. },
  3088. CommentDisplayType() {
  3089. return CommentDisplayType;
  3090. },
  3091. isNew() {
  3092. return this.config.version < DefaultVal.currentVersion && window.isDeadline;
  3093. }
  3094. },
  3095. watch: {
  3096. config: {
  3097. handler(n2) {
  3098. n2.topReplyLoveMinCount = Math.trunc(n2.topReplyLoveMinCount);
  3099. if (n2.topReplyLoveMinCount < 0) {
  3100. n2.topReplyLoveMinCount = 1;
  3101. }
  3102. this.$emit("update:modelValue", n2);
  3103. },
  3104. deep: true
  3105. },
  3106. "config.loopCheckNotice"(n2) {
  3107. if (n2) {
  3108. this.config.loopCheckNoticeInterval = 5;
  3109. this.config.whenNewNoticeGlimmer = false;
  3110. } else {
  3111. this.config.loopCheckNoticeInterval = 0;
  3112. this.config.whenNewNoticeGlimmer = false;
  3113. this.config.ddWebhook = "";
  3114. }
  3115. },
  3116. show(n2) {
  3117. if (n2) {
  3118. if (this.config.version < DefaultVal.currentVersion) {
  3119. $(".v2next-new").remove();
  3120. }
  3121. document.body.style.overflow = "hidden";
  3122. } else {
  3123. document.body.style.overflow = "unset";
  3124. }
  3125. }
  3126. },
  3127. methods: {
  3128. goPost() {
  3129. fetch(DefaultVal.hotUrl + "new.txt").then(async (r2) => {
  3130. let r22 = await r2.text();
  3131. if (r22) {
  3132. functions.openNewTab(r22, true);
  3133. } else {
  3134. functions.openNewTab(DefaultVal.git, true);
  3135. }
  3136. }).catch(() => functions.openNewTab(DefaultVal.git, true));
  3137. },
  3138. close() {
  3139. if (window.isDeadline) {
  3140. this.config.version = DefaultVal.currentVersion;
  3141. }
  3142. this.$emit("update:show", false);
  3143. },
  3144. exportCollectList() {
  3145. if (!this.isLogin) {
  3146. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  3147. }
  3148. try {
  3149. let run2 = function(i) {
  3150. return new Promise((resolve) => {
  3151. $.get(`/my/topics?p=${i}`).then((res) => {
  3152. let body = $(functions.genDomFromHtmlString(res));
  3153. let total = body.find(".page_normal").last().text();
  3154. if (typeof total === "string") {
  3155. total = Number(total);
  3156. }
  3157. let list = [];
  3158. body.find(".topic-link").each(function() {
  3159. let a = functions.parseA(this);
  3160. list.push({
  3161. title: a.title,
  3162. url: location.origin + "/t/" + a.id
  3163. });
  3164. });
  3165. resolve({ list, total });
  3166. });
  3167. });
  3168. };
  3169. let allList = [];
  3170. this.exportLoading = true;
  3171. run2(1).then(async (r2) => {
  3172. allList = allList.concat(r2.list);
  3173. if (r2.total > 1) {
  3174. let getList = [];
  3175. for (let i = 2; i <= r2.total; i++) {
  3176. getList.push(run2(i));
  3177. }
  3178. let b = await Promise.allSettled(getList);
  3179. allList = allList.concat(b.map((v) => v.value.list).flat());
  3180. }
  3181. console.log("all", allList);
  3182. let pom = document.createElement("a");
  3183. pom.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(allList, null, 2)));
  3184. pom.setAttribute("download", "V2EX-收藏.json");
  3185. if (document.createEvent) {
  3186. let event = document.createEvent("MouseEvents");
  3187. event.initEvent("click", true, true);
  3188. pom.dispatchEvent(event);
  3189. } else {
  3190. pom.click();
  3191. }
  3192. this.exportLoading = false;
  3193. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "收藏列表导出成功!" });
  3194. });
  3195. } catch (e2) {
  3196. this.exportLoading = false;
  3197. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "收藏列表导出失败!" });
  3198. }
  3199. },
  3200. importCollectList(e2) {
  3201. if (!this.isLogin) {
  3202. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  3203. }
  3204. let file = e2.target.files[0];
  3205. let fileName = file.name.split(".").pop().toLowerCase();
  3206. console.log("e", file, fileName);
  3207. if (fileName !== "json") {
  3208. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "请导入 json 格式文件!" });
  3209. }
  3210. const reader = new FileReader();
  3211. reader.readAsText(file);
  3212. reader.onload = async () => {
  3213. if (reader.result) {
  3214. try {
  3215. let list = JSON.parse(reader.result);
  3216. console.log(list);
  3217. this.importLoading = true;
  3218. this.total = list.length;
  3219. for (let i = 0; i < list.length; i++) {
  3220. this.endTime = Math.floor((list.length - i) * 10 / 60);
  3221. this.index = i;
  3222. let v = list[i];
  3223. let a = document.createElement("a");
  3224. a.href = v.url;
  3225. let { id } = functions.parseA(a);
  3226. a.remove();
  3227. let apiRes = await fetch(v.url);
  3228. let htmlText = await apiRes.text();
  3229. let hasPermission = htmlText.search("你要查看的页面需要先登录");
  3230. if (hasPermission > -1 || apiRes.status === 404 || apiRes.status === 404 || apiRes.redirected) {
  3231. console.log("无权限", v.url, v.title);
  3232. continue;
  3233. }
  3234. if (htmlText.search("加入收藏") > -1) {
  3235. console.log("未收藏========>>", v.url, v.title);
  3236. let once = await window.fetchOnce();
  3237. let url = `${location.origin}/favorite/topic/${id}?once=${once}`;
  3238. await fetch(url);
  3239. await functions.sleep(1e4);
  3240. } else {
  3241. console.log("已收藏", v.url, v.title);
  3242. }
  3243. await functions.sleep(1e3);
  3244. }
  3245. this.importLoading = false;
  3246. this.importOk = true;
  3247. } catch (e3) {
  3248. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "数据解析失败!" });
  3249. }
  3250. } else {
  3251. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "数据为空!" });
  3252. }
  3253. };
  3254. this.showInput = false;
  3255. setTimeout(() => {
  3256. this.showInput = true;
  3257. }, 200);
  3258. }
  3259. }
  3260. };
  3261. const _withScopeId$a = (n2) => (vue.pushScopeId("data-v-29d88199"), n2 = n2(), vue.popScopeId(), n2);
  3262. const _hoisted_1$f = {
  3263. key: 0,
  3264. class: "setting-modal modal"
  3265. };
  3266. const _hoisted_2$c = { class: "modal-root" };
  3267. const _hoisted_3$a = { class: "modal-header" };
  3268. const _hoisted_4$a = { class: "title" };
  3269. const _hoisted_5$8 = { style: { "font-size": "20px", "text-decoration": "underline" } };
  3270. const _hoisted_6$8 = ["href"];
  3271. const _hoisted_7$7 = {
  3272. key: 0,
  3273. class: "log"
  3274. };
  3275. const _hoisted_8$7 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "new" }, null, -1));
  3276. const _hoisted_9$7 = { class: "body" };
  3277. const _hoisted_10$7 = { class: "left" };
  3278. const _hoisted_11$7 = { class: "tabs" };
  3279. const _hoisted_12$7 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "列表", -1));
  3280. const _hoisted_13$7 = [
  3281. _hoisted_12$7
  3282. ];
  3283. const _hoisted_14$6 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "主题", -1));
  3284. const _hoisted_15$5 = [
  3285. _hoisted_14$6
  3286. ];
  3287. const _hoisted_16$5 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "其他", -1));
  3288. const _hoisted_17$5 = [
  3289. _hoisted_16$5
  3290. ];
  3291. const _hoisted_18$5 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "关于", -1));
  3292. const _hoisted_19$4 = [
  3293. _hoisted_18$5
  3294. ];
  3295. const _hoisted_20$3 = { class: "icons" };
  3296. const _hoisted_21$3 = ["href"];
  3297. const _hoisted_22$3 = ["href"];
  3298. const _hoisted_23$3 = { class: "modal-content" };
  3299. const _hoisted_24$2 = { class: "scroll" };
  3300. const _hoisted_25$1 = { key: 0 };
  3301. const _hoisted_26$1 = { class: "row" };
  3302. const _hoisted_27$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "列表展示方式", -1));
  3303. const _hoisted_28$1 = { class: "wrapper" };
  3304. const _hoisted_29$1 = { class: "radio-group2" };
  3305. const _hoisted_30$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  3306. const _hoisted_31$1 = { class: "row" };
  3307. const _hoisted_32$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "主题弹框显示", -1));
  3308. const _hoisted_33$1 = { class: "wrapper" };
  3309. const _hoisted_34$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  3310. /* @__PURE__ */ vue.createTextVNode(" 开启此选项后,主题会"),
  3311. /* @__PURE__ */ vue.createElementVNode("span", { class: "danger" }, "始终"),
  3312. /* @__PURE__ */ vue.createTextVNode("以弹框的方式显示。优先级大于“新标签页打开链接” ")
  3313. ], -1));
  3314. const _hoisted_35$1 = { class: "row" };
  3315. const _hoisted_36$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "新标签页打开链接", -1));
  3316. const _hoisted_37$1 = { class: "wrapper" };
  3317. const _hoisted_38$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 网页上所有链接通过新标签页打开 ", -1));
  3318. const _hoisted_39$1 = { class: "row" };
  3319. const _hoisted_40$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "打开新标签页时立即切换过去", -1));
  3320. const _hoisted_41$1 = { class: "wrapper" };
  3321. const _hoisted_42$1 = { key: 1 };
  3322. const _hoisted_43$1 = { class: "row" };
  3323. const _hoisted_44$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "回复类型", -1));
  3324. const _hoisted_45$1 = { class: "wrapper" };
  3325. const _hoisted_46$1 = { class: "row" };
  3326. const _hoisted_47$1 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "详情页中显示“回复类型”", -1));
  3327. const _hoisted_48 = { class: "wrapper" };
  3328. const _hoisted_49 = { class: "row" };
  3329. const _hoisted_50 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "替换Imgur源", -1));
  3330. const _hoisted_51 = { class: "wrapper" };
  3331. const _hoisted_52 = { class: "row" };
  3332. const _hoisted_53 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "单独打开主题时默认显示楼中楼", -1));
  3333. const _hoisted_54 = { class: "wrapper" };
  3334. const _hoisted_55 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 单独打开这种地址 https://v2ex.com/t/xxxx 时,是否默认显示楼中楼 ", -1));
  3335. const _hoisted_56 = { class: "row" };
  3336. const _hoisted_57 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "点击左右两侧透明处关闭主题详情弹框", -1));
  3337. const _hoisted_58 = { class: "wrapper" };
  3338. const _hoisted_59 = { class: "row" };
  3339. const _hoisted_60 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "正文超长自动折叠", -1));
  3340. const _hoisted_61 = { class: "wrapper" };
  3341. const _hoisted_62 = { class: "row" };
  3342. const _hoisted_63 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "主题宽度", -1));
  3343. const _hoisted_64 = { class: "wrapper" };
  3344. const _hoisted_65 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  3345. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则默认宽度为77rem。接受合法的width值: "),
  3346. /* @__PURE__ */ vue.createElementVNode("a", {
  3347. href: "https://vue3js.cn/interview/css/em_px_rem_vh_vw.html#%E4%BA%8C%E3%80%81%E5%8D%95%E4%BD%8D",
  3348. target: "_blank"
  3349. }, "rem、px、vw、vh(点此查看)"),
  3350. /* @__PURE__ */ vue.createTextVNode("。 vw代表屏幕百分比,如想要屏幕的66%,请填写66vw ")
  3351. ], -1));
  3352. const _hoisted_66 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 提示:此项设置以后,单独打开详情页时会出现主题突然变宽(窄)的问题,暂时无解 ", -1));
  3353. const _hoisted_67 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  3354. const _hoisted_68 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  3355. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "高赞回复")
  3356. ], -1));
  3357. const _hoisted_69 = { class: "row" };
  3358. const _hoisted_70 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "显示高赞回复", -1));
  3359. const _hoisted_71 = { class: "wrapper" };
  3360. const _hoisted_72 = { class: "row" };
  3361. const _hoisted_73 = { class: "item-title" };
  3362. const _hoisted_74 = { class: "wrapper" };
  3363. const _hoisted_75 = { class: "row" };
  3364. const _hoisted_76 = { class: "item-title" };
  3365. const _hoisted_77 = { class: "wrapper" };
  3366. const _hoisted_78 = { key: 2 };
  3367. const _hoisted_79 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  3368. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "收藏列表")
  3369. ], -1));
  3370. const _hoisted_80 = { class: "row" };
  3371. const _hoisted_81 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("span", null, "   ", -1));
  3372. const _hoisted_82 = { style: { "display": "inline-flex", "overflow": "hidden", "position": "relative" } };
  3373. const _hoisted_83 = {
  3374. key: 0,
  3375. style: { "display": "inline", "margin-left": "10px", "font-size": "18px" }
  3376. };
  3377. const _hoisted_84 = {
  3378. key: 1,
  3379. style: { "display": "inline", "margin-left": "10px" }
  3380. };
  3381. const _hoisted_85 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 默认导出为 json 文件,如需其他格式,请使用 ChatGpt/Deepseek 转换 ", -1));
  3382. const _hoisted_86 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "line" }, null, -1));
  3383. const _hoisted_87 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  3384. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "其他")
  3385. ], -1));
  3386. const _hoisted_88 = { class: "row" };
  3387. const _hoisted_89 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "用户打标签(跨平台,数据保存在自己的记事本):", -1));
  3388. const _hoisted_90 = { class: "wrapper" };
  3389. const _hoisted_91 = { class: "row" };
  3390. const _hoisted_92 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "划词显示Base64解码框", -1));
  3391. const _hoisted_93 = { class: "wrapper" };
  3392. const _hoisted_94 = { class: "row" };
  3393. const _hoisted_95 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自动签到", -1));
  3394. const _hoisted_96 = { class: "wrapper" };
  3395. const _hoisted_97 = { class: "row" };
  3396. const _hoisted_98 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自定义背景", -1));
  3397. const _hoisted_99 = { class: "wrapper" };
  3398. const _hoisted_100 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  3399. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则脚本就什么都不做,V站大部分页面背景颜色默认为 #e2e2e2,少部分页面有特定背景。接受一个合法的css color值:例如"),
  3400. /* @__PURE__ */ vue.createElementVNode("a", {
  3401. href: "https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value",
  3402. target: "_blank"
  3403. }, "red、#ffffff、rgb(222,222,22)(点此查看)"),
  3404. /* @__PURE__ */ vue.createTextVNode("等等。 ")
  3405. ], -1));
  3406. const _hoisted_101 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  3407. const _hoisted_102 = { class: "row" };
  3408. const _hoisted_103 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "收藏时提醒添加到书签", -1));
  3409. const _hoisted_104 = { class: "wrapper" };
  3410. const _hoisted_105 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " V站帐号一旦被封禁,则无法登录,无法查看账号收藏了 ", -1));
  3411. const _hoisted_106 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "line" }, null, -1));
  3412. const _hoisted_107 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  3413. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "消息通知")
  3414. ], -1));
  3415. const _hoisted_108 = { class: "row" };
  3416. const _hoisted_109 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "接管未读提醒页面", -1));
  3417. const _hoisted_110 = { class: "wrapper" };
  3418. const _hoisted_111 = { class: "row" };
  3419. const _hoisted_112 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "定时查询未读提醒", -1));
  3420. const _hoisted_113 = { class: "wrapper" };
  3421. const _hoisted_114 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 开启此功能会带来以下影响: 1、你的IP可能会被封禁 2、消耗更多流量,给服务器带来更大的负担 3、你的V站浏览进度条会变快 ", -1));
  3422. const _hoisted_115 = {
  3423. key: 0,
  3424. class: "sub-content"
  3425. };
  3426. const _hoisted_116 = { class: "row" };
  3427. const _hoisted_117 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "查询间隔", -1));
  3428. const _hoisted_118 = { class: "wrapper" };
  3429. const _hoisted_119 = ["value"];
  3430. const _hoisted_120 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 设置值太小,会导致频繁请求,你的IP可能会被封禁,建议设置为5,即每次5分钟查询一次 ", -1));
  3431. const _hoisted_121 = { class: "row" };
  3432. const _hoisted_122 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "当有新未读提醒时,网页标题闪烁", -1));
  3433. const _hoisted_123 = { class: "wrapper" };
  3434. const _hoisted_124 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  3435. /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "钉钉Webhook地址")
  3436. ], -1));
  3437. const _hoisted_125 = { class: "desc" };
  3438. const _hoisted_126 = ["value"];
  3439. const _hoisted_127 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  3440. const _hoisted_128 = { key: 3 };
  3441. const _hoisted_129 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("h1", null, "V2EX Next", -1));
  3442. const _hoisted_130 = { class: "project-desc" };
  3443. const _hoisted_131 = { style: { "line-height": "2" } };
  3444. const _hoisted_132 = ["href"];
  3445. const _hoisted_133 = ["href"];
  3446. const _hoisted_134 = ["href"];
  3447. const _hoisted_135 = ["href"];
  3448. const _hoisted_136 = ["href"];
  3449. const _hoisted_137 = ["href"];
  3450. function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
  3451. const _component_Icon = vue.resolveComponent("Icon");
  3452. const _component_BaseSwitch = vue.resolveComponent("BaseSwitch");
  3453. const _component_BaseSelect = vue.resolveComponent("BaseSelect");
  3454. const _component_BaseButton = vue.resolveComponent("BaseButton");
  3455. const _component_NoticeModal = vue.resolveComponent("NoticeModal");
  3456. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  3457. default: vue.withCtx(() => [
  3458. $props.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$f, [
  3459. vue.createElementVNode("div", {
  3460. class: "mask",
  3461. onClick: _cache[0] || (_cache[0] = (...args) => $options.close && $options.close(...args))
  3462. }),
  3463. vue.createElementVNode("div", _hoisted_2$c, [
  3464. vue.createElementVNode("div", _hoisted_3$a, [
  3465. vue.createElementVNode("div", _hoisted_4$a, [
  3466. vue.createTextVNode(" 脚本设置 "),
  3467. vue.createElementVNode("div", _hoisted_5$8, [
  3468. vue.createElementVNode("a", {
  3469. href: $options.DefaultVal.mobileScript,
  3470. target: "_blank"
  3471. }, "(手机App已发布,支持楼中楼!)", 8, _hoisted_6$8)
  3472. ])
  3473. ]),
  3474. vue.createVNode(_component_Icon, {
  3475. icon: "ic:round-close",
  3476. onClick: $options.close
  3477. }, null, 8, ["onClick"])
  3478. ]),
  3479. $options.isNew ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7$7, [
  3480. vue.createElementVNode("a", {
  3481. onClick: _cache[1] || (_cache[1] = (...args) => $options.goPost && $options.goPost(...args))
  3482. }, "New:手机App现已发布,支持楼中楼!PC脚本新增历史最热数据、imgur换源功能!点击查看详细介绍"),
  3483. _hoisted_8$7
  3484. ])) : vue.createCommentVNode("", true),
  3485. vue.createElementVNode("div", _hoisted_9$7, [
  3486. vue.createElementVNode("div", _hoisted_10$7, [
  3487. vue.createElementVNode("div", _hoisted_11$7, [
  3488. vue.createElementVNode("div", {
  3489. class: vue.normalizeClass(["tab", $data.tabIndex === 0 && "active"]),
  3490. onClick: _cache[2] || (_cache[2] = ($event) => $data.tabIndex = 0)
  3491. }, _hoisted_13$7, 2),
  3492. vue.createElementVNode("div", {
  3493. class: vue.normalizeClass(["tab", $data.tabIndex === 1 && "active"]),
  3494. onClick: _cache[3] || (_cache[3] = ($event) => $data.tabIndex = 1)
  3495. }, _hoisted_15$5, 2),
  3496. vue.createElementVNode("div", {
  3497. class: vue.normalizeClass(["tab", $data.tabIndex === 2 && "active"]),
  3498. onClick: _cache[4] || (_cache[4] = ($event) => $data.tabIndex = 2)
  3499. }, _hoisted_17$5, 2),
  3500. vue.createElementVNode("div", {
  3501. class: vue.normalizeClass(["tab", $data.tabIndex === 3 && "active"]),
  3502. onClick: _cache[5] || (_cache[5] = ($event) => $data.tabIndex = 3)
  3503. }, _hoisted_19$4, 2)
  3504. ]),
  3505. vue.createElementVNode("div", _hoisted_20$3, [
  3506. vue.createElementVNode("a", {
  3507. href: $options.DefaultVal.git,
  3508. target: "_blank"
  3509. }, [
  3510. vue.createVNode(_component_Icon, { icon: "mdi:github" })
  3511. ], 8, _hoisted_21$3),
  3512. vue.createElementVNode("a", {
  3513. href: $options.DefaultVal.homeUrl,
  3514. target: "_blank"
  3515. }, [
  3516. vue.createVNode(_component_Icon, { icon: "iconamoon:home-light" })
  3517. ], 8, _hoisted_22$3)
  3518. ])
  3519. ]),
  3520. vue.createElementVNode("div", _hoisted_23$3, [
  3521. vue.createElementVNode("div", _hoisted_24$2, [
  3522. $data.tabIndex === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_25$1, [
  3523. vue.createElementVNode("div", _hoisted_26$1, [
  3524. _hoisted_27$1,
  3525. vue.createElementVNode("div", _hoisted_28$1, [
  3526. vue.createElementVNode("div", _hoisted_29$1, [
  3527. vue.createElementVNode("div", {
  3528. class: vue.normalizeClass(["radio", $data.config.viewType === "simple" ? "active" : ""]),
  3529. onClick: _cache[6] || (_cache[6] = ($event) => $data.config.viewType = "simple")
  3530. }, "简洁 ", 2),
  3531. vue.createElementVNode("div", {
  3532. class: vue.normalizeClass(["radio", $data.config.viewType === "table" ? "active" : ""]),
  3533. onClick: _cache[7] || (_cache[7] = ($event) => $data.config.viewType = "table")
  3534. }, "表格 ", 2),
  3535. vue.createElementVNode("div", {
  3536. class: vue.normalizeClass(["radio", $data.config.viewType === "card" ? "active" : ""]),
  3537. onClick: _cache[8] || (_cache[8] = ($event) => $data.showNotice = true)
  3538. }, "卡片 ", 2)
  3539. ])
  3540. ])
  3541. ]),
  3542. _hoisted_30$1,
  3543. vue.createElementVNode("div", _hoisted_31$1, [
  3544. _hoisted_32$1,
  3545. vue.createElementVNode("div", _hoisted_33$1, [
  3546. vue.createVNode(_component_BaseSwitch, {
  3547. modelValue: $data.config.clickPostItemOpenDetail,
  3548. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => $data.config.clickPostItemOpenDetail = $event)
  3549. }, null, 8, ["modelValue"])
  3550. ])
  3551. ]),
  3552. _hoisted_34$1,
  3553. vue.createElementVNode("div", _hoisted_35$1, [
  3554. _hoisted_36$1,
  3555. vue.createElementVNode("div", _hoisted_37$1, [
  3556. vue.createVNode(_component_BaseSwitch, {
  3557. modelValue: $data.config.newTabOpen,
  3558. "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => $data.config.newTabOpen = $event)
  3559. }, null, 8, ["modelValue"])
  3560. ])
  3561. ]),
  3562. _hoisted_38$1,
  3563. vue.createElementVNode("div", _hoisted_39$1, [
  3564. _hoisted_40$1,
  3565. vue.createElementVNode("div", _hoisted_41$1, [
  3566. vue.createVNode(_component_BaseSwitch, {
  3567. modelValue: $data.config.newTabOpenActive,
  3568. "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => $data.config.newTabOpenActive = $event)
  3569. }, null, 8, ["modelValue"])
  3570. ])
  3571. ])
  3572. ])) : vue.createCommentVNode("", true),
  3573. $data.tabIndex === 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_42$1, [
  3574. vue.createElementVNode("div", _hoisted_43$1, [
  3575. _hoisted_44$1,
  3576. vue.createElementVNode("div", _hoisted_45$1, [
  3577. vue.createVNode(_component_BaseSelect, {
  3578. "display-type": $data.config.commentDisplayType,
  3579. "onUpdate:displayType": _cache[12] || (_cache[12] = ($event) => $data.config.commentDisplayType = $event)
  3580. }, null, 8, ["display-type"])
  3581. ])
  3582. ]),
  3583. vue.createElementVNode("div", _hoisted_46$1, [
  3584. _hoisted_47$1,
  3585. vue.createElementVNode("div", _hoisted_48, [
  3586. vue.createVNode(_component_BaseSwitch, {
  3587. modelValue: $data.config.showToolbar,
  3588. "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => $data.config.showToolbar = $event)
  3589. }, null, 8, ["modelValue"])
  3590. ])
  3591. ]),
  3592. vue.createElementVNode("div", _hoisted_49, [
  3593. _hoisted_50,
  3594. vue.createElementVNode("div", _hoisted_51, [
  3595. vue.createVNode(_component_BaseSwitch, {
  3596. modelValue: $data.config.replaceImgur,
  3597. "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.config.replaceImgur = $event)
  3598. }, null, 8, ["modelValue"])
  3599. ])
  3600. ]),
  3601. vue.createElementVNode("div", _hoisted_52, [
  3602. _hoisted_53,
  3603. vue.createElementVNode("div", _hoisted_54, [
  3604. vue.createVNode(_component_BaseSwitch, {
  3605. modelValue: $data.config.autoOpenDetail,
  3606. "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => $data.config.autoOpenDetail = $event)
  3607. }, null, 8, ["modelValue"])
  3608. ])
  3609. ]),
  3610. _hoisted_55,
  3611. vue.createElementVNode("div", _hoisted_56, [
  3612. _hoisted_57,
  3613. vue.createElementVNode("div", _hoisted_58, [
  3614. vue.createVNode(_component_BaseSwitch, {
  3615. modelValue: $data.config.closePostDetailBySpace,
  3616. "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => $data.config.closePostDetailBySpace = $event)
  3617. }, null, 8, ["modelValue"])
  3618. ])
  3619. ]),
  3620. vue.createElementVNode("div", _hoisted_59, [
  3621. _hoisted_60,
  3622. vue.createElementVNode("div", _hoisted_61, [
  3623. vue.createVNode(_component_BaseSwitch, {
  3624. modelValue: $data.config.contentAutoCollapse,
  3625. "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => $data.config.contentAutoCollapse = $event)
  3626. }, null, 8, ["modelValue"])
  3627. ])
  3628. ]),
  3629. vue.createElementVNode("div", _hoisted_62, [
  3630. _hoisted_63,
  3631. vue.createElementVNode("div", _hoisted_64, [
  3632. vue.withDirectives(vue.createElementVNode("input", {
  3633. type: "text",
  3634. "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => $data.config.postWidth = $event)
  3635. }, null, 512), [
  3636. [vue.vModelText, $data.config.postWidth]
  3637. ])
  3638. ])
  3639. ]),
  3640. _hoisted_65,
  3641. _hoisted_66,
  3642. _hoisted_67,
  3643. _hoisted_68,
  3644. vue.createElementVNode("div", _hoisted_69, [
  3645. _hoisted_70,
  3646. vue.createElementVNode("div", _hoisted_71, [
  3647. vue.createVNode(_component_BaseSwitch, {
  3648. modelValue: $data.config.showTopReply,
  3649. "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => $data.config.showTopReply = $event)
  3650. }, null, 8, ["modelValue"])
  3651. ])
  3652. ]),
  3653. vue.createElementVNode("div", _hoisted_72, [
  3654. vue.createElementVNode("label", _hoisted_73, "最多显示" + vue.toDisplayString($data.config.topReplyCount) + "个高赞回复", 1),
  3655. vue.createElementVNode("div", _hoisted_74, [
  3656. vue.withDirectives(vue.createElementVNode("input", {
  3657. type: "number",
  3658. min: "1",
  3659. "onUpdate:modelValue": _cache[20] || (_cache[20] = ($event) => $data.config.topReplyCount = $event)
  3660. }, null, 512), [
  3661. [vue.vModelText, $data.config.topReplyCount]
  3662. ])
  3663. ])
  3664. ]),
  3665. vue.createElementVNode("div", _hoisted_75, [
  3666. vue.createElementVNode("label", _hoisted_76, "最少需要" + vue.toDisplayString($data.config.topReplyLoveMinCount) + "个赞才能被判定为高赞", 1),
  3667. vue.createElementVNode("div", _hoisted_77, [
  3668. vue.withDirectives(vue.createElementVNode("input", {
  3669. type: "number",
  3670. min: "1",
  3671. "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => $data.config.topReplyLoveMinCount = $event)
  3672. }, null, 512), [
  3673. [vue.vModelText, $data.config.topReplyLoveMinCount]
  3674. ])
  3675. ])
  3676. ])
  3677. ])) : vue.createCommentVNode("", true),
  3678. $data.tabIndex === 2 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_78, [
  3679. _hoisted_79,
  3680. vue.createElementVNode("div", _hoisted_80, [
  3681. vue.createElementVNode("div", null, [
  3682. vue.createVNode(_component_BaseButton, {
  3683. onClick: $options.exportCollectList,
  3684. loading: $data.exportLoading
  3685. }, {
  3686. default: vue.withCtx(() => [
  3687. vue.createTextVNode("导出")
  3688. ]),
  3689. _: 1
  3690. }, 8, ["onClick", "loading"]),
  3691. _hoisted_81,
  3692. vue.createElementVNode("div", _hoisted_82, [
  3693. vue.createVNode(_component_BaseButton, { loading: $data.importLoading }, {
  3694. default: vue.withCtx(() => [
  3695. vue.createTextVNode("导入,并收藏")
  3696. ]),
  3697. _: 1
  3698. }, 8, ["loading"]),
  3699. $data.showInput ? (vue.openBlock(), vue.createElementBlock("input", {
  3700. key: 0,
  3701. type: "file",
  3702. style: { "position": "absolute", "width": "100%", "height": "100px", "opacity": "0" },
  3703. onChange: _cache[22] || (_cache[22] = (...args) => $options.importCollectList && $options.importCollectList(...args))
  3704. }, null, 32)) : vue.createCommentVNode("", true)
  3705. ]),
  3706. $data.importLoading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_83, " 导入中:" + vue.toDisplayString($data.index) + "/" + vue.toDisplayString($data.total) + " ,大约需要" + vue.toDisplayString($data.endTime) + "分钟,导入完成前请勿关闭和刷新本页面 ", 1)) : vue.createCommentVNode("", true),
  3707. $data.importOk ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_84, " 导入完成 ")) : vue.createCommentVNode("", true)
  3708. ])
  3709. ]),
  3710. _hoisted_85,
  3711. _hoisted_86,
  3712. _hoisted_87,
  3713. vue.createElementVNode("div", _hoisted_88, [
  3714. _hoisted_89,
  3715. vue.createElementVNode("div", _hoisted_90, [
  3716. vue.createVNode(_component_BaseSwitch, {
  3717. modelValue: $data.config.openTag,
  3718. "onUpdate:modelValue": _cache[23] || (_cache[23] = ($event) => $data.config.openTag = $event)
  3719. }, null, 8, ["modelValue"])
  3720. ])
  3721. ]),
  3722. vue.createElementVNode("div", _hoisted_91, [
  3723. _hoisted_92,
  3724. vue.createElementVNode("div", _hoisted_93, [
  3725. vue.createVNode(_component_BaseSwitch, {
  3726. modelValue: $data.config.base64,
  3727. "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => $data.config.base64 = $event)
  3728. }, null, 8, ["modelValue"])
  3729. ])
  3730. ]),
  3731. vue.createElementVNode("div", _hoisted_94, [
  3732. _hoisted_95,
  3733. vue.createElementVNode("div", _hoisted_96, [
  3734. vue.createVNode(_component_BaseSwitch, {
  3735. modelValue: $data.config.autoSignin,
  3736. "onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => $data.config.autoSignin = $event)
  3737. }, null, 8, ["modelValue"])
  3738. ])
  3739. ]),
  3740. vue.createElementVNode("div", _hoisted_97, [
  3741. _hoisted_98,
  3742. vue.createElementVNode("div", _hoisted_99, [
  3743. vue.withDirectives(vue.createElementVNode("input", {
  3744. type: "text",
  3745. "onUpdate:modelValue": _cache[26] || (_cache[26] = ($event) => $data.config.customBgColor = $event)
  3746. }, null, 512), [
  3747. [vue.vModelText, $data.config.customBgColor]
  3748. ])
  3749. ])
  3750. ]),
  3751. _hoisted_100,
  3752. _hoisted_101,
  3753. vue.createElementVNode("div", _hoisted_102, [
  3754. _hoisted_103,
  3755. vue.createElementVNode("div", _hoisted_104, [
  3756. vue.createVNode(_component_BaseSwitch, {
  3757. modelValue: $data.config.collectBrowserNotice,
  3758. "onUpdate:modelValue": _cache[27] || (_cache[27] = ($event) => $data.config.collectBrowserNotice = $event)
  3759. }, null, 8, ["modelValue"])
  3760. ])
  3761. ]),
  3762. _hoisted_105,
  3763. _hoisted_106,
  3764. _hoisted_107,
  3765. vue.createElementVNode("div", _hoisted_108, [
  3766. _hoisted_109,
  3767. vue.createElementVNode("div", _hoisted_110, [
  3768. vue.createVNode(_component_BaseSwitch, {
  3769. modelValue: $data.config.notice.takeOverNoticePage,
  3770. "onUpdate:modelValue": _cache[28] || (_cache[28] = ($event) => $data.config.notice.takeOverNoticePage = $event)
  3771. }, null, 8, ["modelValue"])
  3772. ])
  3773. ]),
  3774. vue.createElementVNode("div", _hoisted_111, [
  3775. _hoisted_112,
  3776. vue.createElementVNode("div", _hoisted_113, [
  3777. vue.createVNode(_component_BaseSwitch, {
  3778. modelValue: $data.config.notice.loopCheckNotice,
  3779. "onUpdate:modelValue": _cache[29] || (_cache[29] = ($event) => $data.config.notice.loopCheckNotice = $event)
  3780. }, null, 8, ["modelValue"])
  3781. ])
  3782. ]),
  3783. _hoisted_114,
  3784. $data.config.notice.loopCheckNotice ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_115, [
  3785. vue.createElementVNode("div", _hoisted_116, [
  3786. _hoisted_117,
  3787. vue.createElementVNode("div", _hoisted_118, [
  3788. vue.createElementVNode("input", {
  3789. type: "number",
  3790. value: $data.config.notice.loopCheckNoticeInterval,
  3791. onBlur: _cache[30] || (_cache[30] = (e2) => $data.config.notice.loopCheckNoticeInterval = e2.target.value),
  3792. style: { "margin-right": "1rem" }
  3793. }, null, 40, _hoisted_119),
  3794. vue.createTextVNode("分钟 ")
  3795. ])
  3796. ]),
  3797. _hoisted_120,
  3798. vue.createElementVNode("div", _hoisted_121, [
  3799. _hoisted_122,
  3800. vue.createElementVNode("div", _hoisted_123, [
  3801. vue.createVNode(_component_BaseSwitch, {
  3802. modelValue: $data.config.notice.whenNewNoticeGlimmer,
  3803. "onUpdate:modelValue": _cache[31] || (_cache[31] = ($event) => $data.config.notice.whenNewNoticeGlimmer = $event)
  3804. }, null, 8, ["modelValue"])
  3805. ])
  3806. ]),
  3807. _hoisted_124,
  3808. vue.createElementVNode("div", _hoisted_125, [
  3809. vue.createElementVNode("input", {
  3810. type: "text",
  3811. value: $data.config.notice.ddWebhook,
  3812. onBlur: _cache[32] || (_cache[32] = (e2) => $data.config.notice.ddWebhook = e2.target.value),
  3813. style: { "width": "100%" }
  3814. }, null, 40, _hoisted_126)
  3815. ])
  3816. ])) : vue.createCommentVNode("", true),
  3817. _hoisted_127
  3818. ])) : vue.createCommentVNode("", true),
  3819. $data.tabIndex === 3 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_128, [
  3820. _hoisted_129,
  3821. vue.createElementVNode("div", _hoisted_130, [
  3822. vue.createElementVNode("div", _hoisted_131, [
  3823. vue.createElementVNode("div", null, [
  3824. vue.createTextVNode("官网:"),
  3825. vue.createElementVNode("a", {
  3826. href: $options.DefaultVal.homeUrl,
  3827. target: "_blank"
  3828. }, vue.toDisplayString($options.DefaultVal.homeUrl), 9, _hoisted_132)
  3829. ]),
  3830. vue.createElementVNode("div", null, [
  3831. vue.createTextVNode("GitHub地址:"),
  3832. vue.createElementVNode("a", {
  3833. href: $options.DefaultVal.git,
  3834. target: "_blank"
  3835. }, vue.toDisplayString($options.DefaultVal.git), 9, _hoisted_133)
  3836. ]),
  3837. vue.createElementVNode("div", null, [
  3838. vue.createTextVNode("PC脚本地址:"),
  3839. vue.createElementVNode("a", {
  3840. href: $options.DefaultVal.pcScript,
  3841. target: "_blank"
  3842. }, vue.toDisplayString($options.DefaultVal.pcScript), 9, _hoisted_134)
  3843. ]),
  3844. vue.createElementVNode("div", null, [
  3845. vue.createTextVNode("App地址:"),
  3846. vue.createElementVNode("a", {
  3847. href: $options.DefaultVal.mobileScript,
  3848. target: "_blank"
  3849. }, vue.toDisplayString($options.DefaultVal.mobileScript), 9, _hoisted_135)
  3850. ]),
  3851. vue.createElementVNode("div", null, [
  3852. vue.createTextVNode("反馈: "),
  3853. vue.createElementVNode("a", {
  3854. href: $options.DefaultVal.issue,
  3855. target: "_blank"
  3856. }, vue.toDisplayString($options.DefaultVal.issue), 9, _hoisted_136)
  3857. ]),
  3858. vue.createElementVNode("div", null, [
  3859. vue.createTextVNode("更新日志:"),
  3860. vue.createElementVNode("a", {
  3861. href: $options.DefaultVal.pcLog,
  3862. target: "_blank"
  3863. }, vue.toDisplayString($options.DefaultVal.pcLog), 9, _hoisted_137)
  3864. ])
  3865. ])
  3866. ])
  3867. ])) : vue.createCommentVNode("", true)
  3868. ])
  3869. ])
  3870. ])
  3871. ]),
  3872. vue.createVNode(_component_NoticeModal, {
  3873. show: $data.showNotice,
  3874. "onUpdate:show": _cache[33] || (_cache[33] = ($event) => $data.showNotice = $event),
  3875. onConfirm: _cache[34] || (_cache[34] = ($event) => $data.config.viewType = "card")
  3876. }, null, 8, ["show"])
  3877. ])) : vue.createCommentVNode("", true)
  3878. ]),
  3879. _: 1
  3880. });
  3881. }
  3882. const Setting = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["render", _sfc_render$8], ["__scopeId", "data-v-29d88199"]]);
  3883. const _sfc_main$e = {
  3884. name: "Point",
  3885. components: { PopConfirm, Icon },
  3886. inject: ["post", "isLogin"],
  3887. props: {
  3888. item: {
  3889. type: Object,
  3890. default() {
  3891. return {};
  3892. }
  3893. },
  3894. apiUrl: ""
  3895. },
  3896. computed: {
  3897. disabled() {
  3898. return this.item.username === window.user.username || this.item.isThanked || !this.isLogin;
  3899. }
  3900. },
  3901. methods: {
  3902. thankError() {
  3903. if (!this.isLogin) {
  3904. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  3905. }
  3906. if (this.item.username === window.user.username) {
  3907. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "不能感谢自己" });
  3908. }
  3909. if (this.item.isThanked) {
  3910. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "已经感谢过了" });
  3911. }
  3912. },
  3913. async thank() {
  3914. this.$emit("addThank");
  3915. let url = `${location.origin}/thank/${this.apiUrl}?once=${this.post.once}`;
  3916. $.post(url).then((res) => {
  3917. if (!res.success) {
  3918. this.$emit("recallThank");
  3919. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: res.message });
  3920. }
  3921. eventBus.emit(CMD.REFRESH_ONCE, res.once);
  3922. }, (err) => {
  3923. this.$emit("recallThank");
  3924. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "感谢失败" });
  3925. eventBus.emit(CMD.REFRESH_ONCE);
  3926. });
  3927. }
  3928. }
  3929. };
  3930. const _hoisted_1$e = {
  3931. key: 2,
  3932. class: "link-num"
  3933. };
  3934. const _hoisted_2$b = { key: 3 };
  3935. function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
  3936. const _component_Icon = vue.resolveComponent("Icon");
  3937. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  3938. return vue.openBlock(), vue.createBlock(_component_PopConfirm, {
  3939. disabled: $options.disabled,
  3940. title: `确认花费 10 个铜币向 @${$props.item.username} 的这条回复发送感谢?`,
  3941. onConfirm: $options.thank
  3942. }, {
  3943. default: vue.withCtx(() => [
  3944. vue.createElementVNode("div", {
  3945. class: vue.normalizeClass(["tool", [$options.disabled && "disabled"]]),
  3946. onClick: _cache[0] || (_cache[0] = (...args) => $options.thankError && $options.thankError(...args))
  3947. }, [
  3948. $props.item.isThanked ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  3949. key: 0,
  3950. color: "rgb(224,42,42)",
  3951. icon: "icon-park-solid:like"
  3952. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  3953. key: 1,
  3954. color: !$props.item.thankCount ? null : "rgb(224,42,42)",
  3955. icon: "icon-park-outline:like"
  3956. }, null, 8, ["color"])),
  3957. $props.item.thankCount ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_1$e, vue.toDisplayString($props.item.thankCount), 1)) : (vue.openBlock(), vue.createElementBlock("span", _hoisted_2$b, "感谢"))
  3958. ], 2)
  3959. ]),
  3960. _: 1
  3961. }, 8, ["disabled", "title", "onConfirm"]);
  3962. }
  3963. const Point = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$7]]);
  3964. const _sfc_main$d = {
  3965. name: "Author",
  3966. components: { PopConfirm, Point, Icon },
  3967. inject: ["isLogin", "tags", "config", "isNight"],
  3968. props: {
  3969. modelValue: false,
  3970. comment: {
  3971. type: Object,
  3972. default() {
  3973. return {};
  3974. }
  3975. },
  3976. type: {
  3977. type: String,
  3978. default() {
  3979. return "list";
  3980. }
  3981. }
  3982. },
  3983. computed: {
  3984. isDev() {
  3985. return false;
  3986. },
  3987. pointInfo() {
  3988. return {
  3989. isThanked: this.comment.isThanked,
  3990. thankCount: this.comment.thankCount,
  3991. username: this.comment.username
  3992. };
  3993. },
  3994. myTags() {
  3995. return this.tags[this.comment.username] ?? [];
  3996. },
  3997. context() {
  3998. return this.comment.replyUsers.length;
  3999. }
  4000. },
  4001. methods: {
  4002. jump() {
  4003. eventBus.emit(CMD.JUMP, this.comment.floor);
  4004. },
  4005. showRelationReply() {
  4006. if (!this.comment.replyUsers.length) {
  4007. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "该回复无上下文" });
  4008. return;
  4009. }
  4010. eventBus.emit(CMD.RELATION_REPLY, {
  4011. left: this.comment.replyUsers,
  4012. right: this.comment.username,
  4013. rightFloor: this.comment.floor
  4014. });
  4015. },
  4016. addTag() {
  4017. eventBus.emit(CMD.ADD_TAG, this.comment.username);
  4018. },
  4019. removeTag(tag) {
  4020. eventBus.emit(CMD.REMOVE_TAG, { username: this.comment.username, tag });
  4021. },
  4022. checkIsLogin(emitName = "") {
  4023. if (!this.isLogin) {
  4024. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  4025. return false;
  4026. }
  4027. this.$emit(emitName);
  4028. return true;
  4029. },
  4030. addThank() {
  4031. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "add" });
  4032. },
  4033. recallThank() {
  4034. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "recall" });
  4035. }
  4036. }
  4037. };
  4038. const _withScopeId$9 = (n2) => (vue.pushScopeId("data-v-64aa1930"), n2 = n2(), vue.popScopeId(), n2);
  4039. const _hoisted_1$d = { class: "Author-left" };
  4040. const _hoisted_2$a = ["href"];
  4041. const _hoisted_3$9 = ["src"];
  4042. const _hoisted_4$9 = { class: "texts" };
  4043. const _hoisted_5$7 = ["href"];
  4044. const _hoisted_6$7 = {
  4045. key: 0,
  4046. class: "owner"
  4047. };
  4048. const _hoisted_7$6 = {
  4049. key: 1,
  4050. class: "dup"
  4051. };
  4052. const _hoisted_8$6 = {
  4053. key: 2,
  4054. class: "mod"
  4055. };
  4056. const _hoisted_9$6 = { class: "ago" };
  4057. const _hoisted_10$6 = { class: "my-tag" };
  4058. const _hoisted_11$6 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  4059. const _hoisted_12$6 = ["onClick"];
  4060. const _hoisted_13$6 = { class: "Author-right" };
  4061. const _hoisted_14$5 = {
  4062. key: 0,
  4063. class: "toolbar"
  4064. };
  4065. const _hoisted_15$4 = { class: "tool" };
  4066. const _hoisted_16$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "隐藏", -1));
  4067. const _hoisted_17$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上下文", -1));
  4068. const _hoisted_18$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  4069. const _hoisted_19$3 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复", -1));
  4070. function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
  4071. const _component_Icon = vue.resolveComponent("Icon");
  4072. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  4073. const _component_Point = vue.resolveComponent("Point");
  4074. return vue.openBlock(), vue.createElementBlock("div", {
  4075. class: vue.normalizeClass(["Author", { expand: !$props.modelValue }])
  4076. }, [
  4077. vue.createElementVNode("div", _hoisted_1$d, [
  4078. !$props.modelValue ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  4079. key: 0,
  4080. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => _ctx.$emit("update:modelValue", true), ["stop"])),
  4081. color: "#177EC9",
  4082. class: "expand-icon",
  4083. icon: "gravity-ui:chevrons-expand-up-right"
  4084. })) : vue.createCommentVNode("", true),
  4085. $options.config.viewType !== "simple" ? (vue.openBlock(), vue.createElementBlock("a", {
  4086. key: 1,
  4087. class: "avatar",
  4088. href: `/member/${$props.comment.username}`
  4089. }, [
  4090. vue.createElementVNode("img", {
  4091. src: $props.comment.avatar,
  4092. alt: ""
  4093. }, null, 8, _hoisted_3$9)
  4094. ], 8, _hoisted_2$a)) : vue.createCommentVNode("", true),
  4095. vue.createElementVNode("span", _hoisted_4$9, [
  4096. vue.createElementVNode("strong", null, [
  4097. vue.createElementVNode("a", {
  4098. href: `/member/${$props.comment.username}`,
  4099. class: vue.normalizeClass(["username", { "dark": $options.isNight }])
  4100. }, vue.toDisplayString($props.comment.username), 11, _hoisted_5$7)
  4101. ]),
  4102. $props.comment.isOp ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6$7, "OP")) : vue.createCommentVNode("", true),
  4103. $props.comment.isDup ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7$6, "DUP")) : vue.createCommentVNode("", true),
  4104. $props.comment.isMod ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8$6, "MOD")) : vue.createCommentVNode("", true),
  4105. vue.createElementVNode("span", _hoisted_9$6, vue.toDisplayString($props.comment.date), 1),
  4106. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 3 }, [
  4107. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  4108. return vue.openBlock(), vue.createElementBlock("span", _hoisted_10$6, [
  4109. _hoisted_11$6,
  4110. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  4111. vue.createElementVNode("i", {
  4112. class: "fa fa-trash-o remove",
  4113. onClick: vue.withModifiers(($event) => $options.removeTag(i), ["stop"])
  4114. }, null, 8, _hoisted_12$6)
  4115. ]);
  4116. }), 256)),
  4117. vue.createElementVNode("span", {
  4118. class: "add-tag ago",
  4119. onClick: _cache[1] || (_cache[1] = vue.withModifiers((...args) => $options.addTag && $options.addTag(...args), ["stop"])),
  4120. title: "添加标签"
  4121. }, "+")
  4122. ], 64)) : vue.createCommentVNode("", true)
  4123. ])
  4124. ]),
  4125. vue.createElementVNode("div", _hoisted_13$6, [
  4126. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$5, [
  4127. vue.createVNode(_component_PopConfirm, {
  4128. title: "确认隐藏这条回复?",
  4129. onConfirm: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("hide"))
  4130. }, {
  4131. default: vue.withCtx(() => [
  4132. vue.createElementVNode("div", _hoisted_15$4, [
  4133. vue.createVNode(_component_Icon, { icon: "fluent:eye-hide-24-regular" }),
  4134. _hoisted_16$4
  4135. ])
  4136. ]),
  4137. _: 1
  4138. }),
  4139. $options.context ? (vue.openBlock(), vue.createElementBlock("div", {
  4140. key: 0,
  4141. class: "tool",
  4142. onClick: _cache[3] || (_cache[3] = vue.withModifiers((...args) => $options.showRelationReply && $options.showRelationReply(...args), ["stop"]))
  4143. }, [
  4144. vue.createVNode(_component_Icon, { icon: "iconoir:page-search" }),
  4145. _hoisted_17$4
  4146. ])) : vue.createCommentVNode("", true),
  4147. $props.type === "top" ? (vue.openBlock(), vue.createElementBlock("div", {
  4148. key: 1,
  4149. class: "tool",
  4150. onClick: _cache[4] || (_cache[4] = vue.withModifiers((...args) => $options.jump && $options.jump(...args), ["stop"]))
  4151. }, [
  4152. vue.createVNode(_component_Icon, { icon: "icon-park-outline:to-bottom" }),
  4153. _hoisted_18$4
  4154. ])) : vue.createCommentVNode("", true),
  4155. vue.createElementVNode("div", {
  4156. class: "tool",
  4157. onClick: _cache[5] || (_cache[5] = vue.withModifiers(($event) => $options.checkIsLogin("reply"), ["stop"]))
  4158. }, [
  4159. vue.createVNode(_component_Icon, { icon: "mynaui:message" }),
  4160. _hoisted_19$3
  4161. ]),
  4162. vue.withDirectives(vue.createVNode(_component_Point, {
  4163. item: $options.pointInfo,
  4164. onAddThank: $options.addThank,
  4165. onRecallThank: $options.recallThank,
  4166. "api-url": "reply/" + $props.comment.id
  4167. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  4168. [vue.vShow, !$props.comment.thankCount]
  4169. ])
  4170. ])) : vue.createCommentVNode("", true),
  4171. vue.withDirectives(vue.createVNode(_component_Point, {
  4172. item: $options.pointInfo,
  4173. onAddThank: $options.addThank,
  4174. onRecallThank: $options.recallThank,
  4175. "api-url": "reply/" + $props.comment.id
  4176. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  4177. [vue.vShow, $props.comment.thankCount]
  4178. ]),
  4179. vue.createElementVNode("div", {
  4180. class: vue.normalizeClass(["floor", { isDev: $options.isDev }])
  4181. }, vue.toDisplayString($props.comment.floor), 3)
  4182. ])
  4183. ], 2);
  4184. }
  4185. const Author = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$6], ["__scopeId", "data-v-64aa1930"]]);
  4186. const _withScopeId$8 = (n2) => (vue.pushScopeId("data-v-85e09b4e"), n2 = n2(), vue.popScopeId(), n2);
  4187. const _hoisted_1$c = { class: "get-cursor" };
  4188. const _hoisted_2$9 = ["innerHTML"];
  4189. const _hoisted_3$8 = { class: "toolbar" };
  4190. const _hoisted_4$8 = { class: "left" };
  4191. const _hoisted_5$6 = { class: "upload" };
  4192. const _hoisted_6$6 = {
  4193. key: 0,
  4194. style: { "color": "black", "font-size": "1.4rem" }
  4195. };
  4196. const _hoisted_7$5 = { class: "right" };
  4197. const _hoisted_8$5 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, "经典", -1));
  4198. const _hoisted_9$5 = { class: "list" };
  4199. const _hoisted_10$5 = ["src", "onClick"];
  4200. const _hoisted_11$5 = { class: "emoji" };
  4201. const _hoisted_12$5 = { class: "title" };
  4202. const _hoisted_13$5 = { class: "list" };
  4203. const _hoisted_14$4 = ["onClick"];
  4204. const _sfc_main$c = {
  4205. __name: "PostEditor",
  4206. props: {
  4207. replyUser: null,
  4208. replyFloor: null,
  4209. useType: {
  4210. type: String,
  4211. default() {
  4212. return "reply-comment";
  4213. }
  4214. }
  4215. },
  4216. emits: ["close"],
  4217. setup(__props, { expose: __expose, emit: __emit }) {
  4218. const props = __props;
  4219. const { replyUser, replyFloor, useType } = props;
  4220. const replyInfo = replyUser ? `@${replyUser} #${replyFloor} ` : "";
  4221. const emits = __emit;
  4222. const post = vue.inject("post");
  4223. const show = vue.inject("show");
  4224. const isNight = vue.inject("isNight");
  4225. vue.inject("pageType");
  4226. const allReplyUsers = vue.inject("allReplyUsers");
  4227. let isFocus = vue.ref(false);
  4228. const loading = vue.ref(false);
  4229. const uploadLoading = vue.ref(false);
  4230. const isShowEmoticons = vue.ref(false);
  4231. const editorId = vue.ref("editorId_" + Date.now());
  4232. const content = vue.ref(replyInfo);
  4233. const txtRef = vue.ref(null);
  4234. const cursorRef = vue.ref(null);
  4235. const emoticonsRef = vue.ref(null);
  4236. const none = vue.ref('<span style="white-space:pre-wrap;"> </span>');
  4237. const imgurClientIdPool = [
  4238. "3107b9ef8b316f3",
  4239. "442b04f26eefc8a",
  4240. "59cfebe717c09e4",
  4241. "60605aad4a62882",
  4242. "6c65ab1d3f5452a",
  4243. "83e123737849aa9",
  4244. "9311f6be1c10160",
  4245. "c4a4a563f698595",
  4246. "81be04b9e4a08ce"
  4247. ];
  4248. __expose({ content, isFocus: () => isFocus.value });
  4249. const editorClass = vue.computed(() => {
  4250. return [useType, isFocus.value ? "isFocus" : "", isNight.value ? "isNight" : ""];
  4251. });
  4252. const cursorHtml = vue.computed(() => {
  4253. var _a;
  4254. if (!txtRef.value || !content.value)
  4255. return "";
  4256. let index = ((_a = txtRef.value) == null ? void 0 : _a.selectionStart) || 0;
  4257. return content.value.substring(0, index).replace(/</g, "<").replace(/>/g, ">").replace(/\n/g, "<br/>").replace(/\s/g, none.value);
  4258. });
  4259. const disabled = vue.computed(() => {
  4260. if (content.value) {
  4261. return content.value === replyInfo;
  4262. } else {
  4263. return true;
  4264. }
  4265. });
  4266. function drop(e2) {
  4267. e2.preventDefault();
  4268. upload(e2.dataTransfer.files[0]);
  4269. }
  4270. async function upload(file) {
  4271. if (!file)
  4272. return;
  4273. if (uploadLoading.value)
  4274. return;
  4275. uploadLoading.value = true;
  4276. const formData = new FormData();
  4277. formData.append("image", file);
  4278. const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
  4279. const clidenId = imgurClientIdPool[randomIndex];
  4280. const res = await fetch("https://api.imgur.com/3/upload", {
  4281. method: "POST",
  4282. headers: { Authorization: `Client-ID ${clidenId}` },
  4283. body: formData
  4284. });
  4285. uploadLoading.value = false;
  4286. if (res.ok) {
  4287. const resData = await res.json();
  4288. if (resData.success) {
  4289. return insert(" " + resData.data.link + " ");
  4290. }
  4291. }
  4292. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "上传失败" });
  4293. }
  4294. async function submit() {
  4295. if (disabled.value || loading.value)
  4296. return;
  4297. loading.value = true;
  4298. let submit_content = content.value.replace(/\[((?!\[).)+\]/g, function(match) {
  4299. let item2 = classicsEmoticons.find((v) => v.name === match);
  4300. if (item2) {
  4301. return item2.low + " ";
  4302. }
  4303. return match;
  4304. });
  4305. let show_content = content.value.replace(/https?:\/\/(i\.)?imgur\.com\/((?!http).)+\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)/g, function(match) {
  4306. return `<img src="${match}" data-originUrl="${match}" data-notice="这个img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`;
  4307. });
  4308. show_content = show_content.replace(/\[((?!\[).)+\]/g, function(match) {
  4309. let item2 = classicsEmoticons.find((v) => v.name === match);
  4310. if (item2) {
  4311. return `<a target="_blank" href="${item2.low}" rel="nofollow noopener"><img src="${item2.low}" class="embedded_image" rel="noreferrer"></a> `;
  4312. }
  4313. return match;
  4314. });
  4315. let matchUsers = show_content.match(/@([\w]+?[\s])/g);
  4316. if (matchUsers) {
  4317. matchUsers.map((i) => {
  4318. let username = i.replace("@", "").replace(" ", "");
  4319. show_content = show_content.replace(username, `<a href="/member/${username}">${username}</a>`);
  4320. });
  4321. }
  4322. show_content = show_content.replaceAll("\n", "<br/>");
  4323. let item = {
  4324. thankCount: 0,
  4325. isThanked: false,
  4326. isOp: post.value.username === window.user.username,
  4327. isDup: false,
  4328. id: Date.now(),
  4329. username: window.user.username,
  4330. avatar: window.user.avatar,
  4331. date: "几秒前",
  4332. floor: post.value.replyCount + 1,
  4333. reply_content: show_content ?? "",
  4334. children: [],
  4335. replyUsers: replyUser ? [replyUser] : [],
  4336. replyFloor: replyFloor || -1,
  4337. level: useType === "reply-comment" ? 1 : 0
  4338. };
  4339. item.hideCallUserReplyContent = item.reply_content;
  4340. if (item.replyUsers.length === 1) {
  4341. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(?:<ul [\s\S]+<\/ul>)?(\s#[\d]+)?\s(<br>)?/, () => "");
  4342. }
  4343. let url = `${location.origin}/t/${post.value.id}`;
  4344. $.post(url, { content: submit_content, once: post.value.once }).then(
  4345. // $.post(url, {content: submit_content, once: 123}).then(
  4346. (res) => {
  4347. loading.value = false;
  4348. let r2 = res.search("你上一条回复的内容和这条相同");
  4349. if (r2 > -1)
  4350. return eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你上一条回复的内容和这条相同" });
  4351. r2 = res.search("请不要在每一个回复中都包括外链,这看起来像是在 spamming");
  4352. if (r2 > -1)
  4353. return eventBus.emit(CMD.SHOW_MSG, {
  4354. type: "error",
  4355. text: "请不要在每一个回复中都包括外链,这看起来像是在 spamming"
  4356. });
  4357. let r22 = res.search("创建新回复");
  4358. if (r22 > -1) {
  4359. eventBus.emit(CMD.REFRESH_ONCE, res);
  4360. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复出现了问题,请使用原版进行回复" });
  4361. let clientWidth = window.document.body.clientWidth;
  4362. let windowWidth = 1200;
  4363. let left = clientWidth / 2 - windowWidth / 2;
  4364. let newWin = window.open("创建新回复", "", `width=${windowWidth},height=600,left=${left},top=100`);
  4365. newWin.document.write(res);
  4366. let loop = setInterval(function() {
  4367. if (newWin.closed) {
  4368. clearInterval(loop);
  4369. eventBus.emit(CMD.REFRESH_POST);
  4370. }
  4371. }, 1e3);
  4372. return;
  4373. }
  4374. content.value = replyInfo;
  4375. emits("close");
  4376. eventBus.emit(CMD.REFRESH_ONCE, res);
  4377. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "回复成功" });
  4378. eventBus.emit(CMD.ADD_REPLY, item);
  4379. },
  4380. (err) => {
  4381. console.log("err", err);
  4382. loading.value = false;
  4383. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
  4384. }
  4385. ).catch((r2) => {
  4386. console.log("catch", r2);
  4387. });
  4388. }
  4389. function getEmojiSrc(url) {
  4390. return window.config.replaceImgur ? DefaultVal.imgurProxy + url : url;
  4391. }
  4392. function showEmoticons(e2) {
  4393. if (isShowEmoticons.value) {
  4394. return isShowEmoticons.value = false;
  4395. }
  4396. let rect = e2.currentTarget.getBoundingClientRect();
  4397. emoticonsRef.value.style.left = rect.left + 30 + "px";
  4398. emoticonsRef.value.style.bottom = window.innerHeight - rect.top - 20 + "px";
  4399. isShowEmoticons.value = true;
  4400. }
  4401. function off() {
  4402. eventBus.emit(CMD.SHOW_CALL, { show: false });
  4403. eventBus.off(CMD.SET_CALL);
  4404. }
  4405. function checkHeight2() {
  4406. txtRef.value.style.height = 0;
  4407. txtRef.value.style.height = txtRef.value.scrollHeight + "px";
  4408. }
  4409. function insert(str) {
  4410. let cursorPos = txtRef.value.selectionStart;
  4411. let start = content.value.slice(0, cursorPos);
  4412. let end = content.value.slice(cursorPos, content.value.length);
  4413. content.value = start + str + end;
  4414. let moveCursorPos = start.length + str.length;
  4415. setTimeout(() => {
  4416. txtRef.value.focus();
  4417. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  4418. checkHeight2();
  4419. });
  4420. }
  4421. function showCallPopover(text) {
  4422. let r2 = cursorRef.value.getBoundingClientRect();
  4423. eventBus.emit(CMD.SHOW_CALL, { show: true, top: r2.top, left: r2.left, text });
  4424. eventBus.off(CMD.SET_CALL);
  4425. eventBus.on(CMD.SET_CALL, (e2) => {
  4426. let cursorPos = txtRef.value.selectionStart;
  4427. let start = content.value.slice(0, cursorPos);
  4428. let end = content.value.slice(cursorPos, content.value.length);
  4429. let lastCallPos = start.lastIndexOf("@");
  4430. start = content.value.slice(0, lastCallPos + 1);
  4431. if (e2 === "管理员") {
  4432. e2 = "Livid @Kai @Olivia @GordianZ @sparanoid @drymonfidelia";
  4433. }
  4434. if (e2 === "所有人") {
  4435. e2 = allReplyUsers.value.map((v, i) => {
  4436. if (i)
  4437. return "@" + v;
  4438. else
  4439. return v;
  4440. }).join(" ");
  4441. }
  4442. content.value = start + e2 + " " + end;
  4443. let moveCursorPos = start.length + e2.length + 1;
  4444. setTimeout(() => {
  4445. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  4446. checkHeight2();
  4447. });
  4448. eventBus.off(CMD.SET_CALL);
  4449. });
  4450. }
  4451. function onKeydown(e2) {
  4452. let code = e2.keyCode;
  4453. switch (code) {
  4454. case 8:
  4455. if (content.value === "@") {
  4456. off();
  4457. }
  4458. break;
  4459. case 37:
  4460. case 38:
  4461. case 39:
  4462. case 40:
  4463. setTimeout(() => onInput({ data: "" }), 100);
  4464. break;
  4465. case 27:
  4466. e2.preventDefault();
  4467. e2.stopPropagation();
  4468. e2.stopImmediatePropagation();
  4469. return false;
  4470. case 13:
  4471. if (e2.ctrlKey)
  4472. submit();
  4473. if (e2.metaKey)
  4474. submit();
  4475. break;
  4476. }
  4477. }
  4478. function onInput(e2) {
  4479. let cursorPos = txtRef.value.selectionStart;
  4480. if (!content.value)
  4481. return;
  4482. if (e2.data === " ") {
  4483. return off();
  4484. }
  4485. if (e2.data === "@") {
  4486. if (content.value.length !== 1) {
  4487. if (content.value[cursorPos - 2] === " " || content.value[cursorPos - 2] === "\n") {
  4488. return showCallPopover("");
  4489. }
  4490. } else {
  4491. return showCallPopover("");
  4492. }
  4493. off();
  4494. } else {
  4495. checkHeight2();
  4496. let judgeStr = content.value.slice(0, cursorPos);
  4497. let lastCallPos = judgeStr.lastIndexOf("@");
  4498. if (lastCallPos === -1) {
  4499. return off();
  4500. }
  4501. let callStr = judgeStr.slice(lastCallPos, cursorPos);
  4502. let hasSpace = callStr.includes(" ");
  4503. if (hasSpace) {
  4504. off();
  4505. } else {
  4506. if (lastCallPos === 0) {
  4507. return showCallPopover(callStr.replace("@", ""));
  4508. }
  4509. if (content.value.length !== 1) {
  4510. if (content.value[lastCallPos - 1] === " " || content.value[lastCallPos - 1] === "\n") {
  4511. return showCallPopover(callStr.replace("@", ""));
  4512. }
  4513. } else {
  4514. return showCallPopover(callStr.replace("@", ""));
  4515. }
  4516. off();
  4517. }
  4518. }
  4519. }
  4520. function onPaste(e2) {
  4521. const dataTransferItemList = e2.clipboardData.items;
  4522. const items = [].slice.call(dataTransferItemList).filter(function(item) {
  4523. return item.type.indexOf("image") !== -1;
  4524. });
  4525. if (items.length === 0) {
  4526. return;
  4527. }
  4528. const dataTransferItem = items[0];
  4529. const blob = dataTransferItem.getAsFile();
  4530. upload(blob);
  4531. }
  4532. function onBlur() {
  4533. document.removeEventListener("paste", onPaste);
  4534. isFocus.value = false;
  4535. }
  4536. function onFocusin() {
  4537. document.addEventListener("paste", onPaste);
  4538. }
  4539. vue.watch(() => show, (n2) => {
  4540. if (n2.value)
  4541. isShowEmoticons.value = false;
  4542. }, { deep: true });
  4543. vue.onMounted(() => {
  4544. $(`.${editorId.value}`).each(function() {
  4545. this.setAttribute("style", "height:" + this.scrollHeight + "px;overflow-y:hidden;");
  4546. }).on("input", function() {
  4547. this.style.height = 0;
  4548. this.style.height = this.scrollHeight + "px";
  4549. });
  4550. if (useType === "reply-comment") {
  4551. txtRef.value && txtRef.value.focus();
  4552. }
  4553. });
  4554. vue.onBeforeUnmount(() => {
  4555. $(`.${editorId.value}`).off();
  4556. });
  4557. return (_ctx, _cache) => {
  4558. return vue.openBlock(), vue.createElementBlock("div", {
  4559. class: vue.normalizeClass(["post-editor-wrapper", editorClass.value])
  4560. }, [
  4561. vue.withDirectives(vue.createElementVNode("textarea", {
  4562. class: vue.normalizeClass(["post-editor", editorId.value]),
  4563. ref_key: "txtRef",
  4564. ref: txtRef,
  4565. onFocus: _cache[0] || (_cache[0] = ($event) => vue.isRef(isFocus) ? isFocus.value = true : isFocus = true),
  4566. onBlur,
  4567. onFocusin,
  4568. placeholder: "请尽量让自己的回复能够对别人有帮助",
  4569. onInput,
  4570. onKeydown,
  4571. onDrop: drop,
  4572. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => content.value = $event)
  4573. }, null, 34), [
  4574. [vue.vModelText, content.value]
  4575. ]),
  4576. vue.createElementVNode("div", _hoisted_1$c, [
  4577. vue.createElementVNode("span", { innerHTML: cursorHtml.value }, null, 8, _hoisted_2$9),
  4578. vue.createElementVNode("span", {
  4579. class: "cursor",
  4580. ref_key: "cursorRef",
  4581. ref: cursorRef
  4582. }, "|", 512)
  4583. ]),
  4584. vue.createElementVNode("div", _hoisted_3$8, [
  4585. vue.createElementVNode("div", _hoisted_4$8, [
  4586. vue.createVNode(vue.unref(Icon), {
  4587. onClick: vue.withModifiers(showEmoticons, ["stop"]),
  4588. icon: "streamline:smiley-happy"
  4589. }),
  4590. vue.createElementVNode("div", _hoisted_5$6, [
  4591. vue.createElementVNode("input", {
  4592. type: "file",
  4593. accept: "image/*",
  4594. onChange: _cache[2] || (_cache[2] = (e2) => upload(e2.currentTarget.files[0]))
  4595. }, null, 32),
  4596. vue.createVNode(vue.unref(Icon), { icon: "lets-icons:img-load-box-fill" })
  4597. ]),
  4598. uploadLoading.value ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_6$6, "上传中.....")) : vue.createCommentVNode("", true)
  4599. ]),
  4600. vue.createElementVNode("div", _hoisted_7$5, [
  4601. vue.unref(useType) === "reply-comment" ? (vue.openBlock(), vue.createBlock(BaseButton, {
  4602. key: 0,
  4603. type: "link",
  4604. size: "small",
  4605. style: { "margin-right": "1rem", "cursor": "pointer" },
  4606. onClick: _cache[3] || (_cache[3] = vue.withModifiers(($event) => emits("close"), ["stop"]))
  4607. }, {
  4608. default: vue.withCtx(() => [
  4609. vue.createTextVNode(" 关闭 ")
  4610. ]),
  4611. _: 1
  4612. })) : vue.createCommentVNode("", true),
  4613. vue.createVNode(BaseButton, {
  4614. size: "small",
  4615. disabled: disabled.value,
  4616. loading: loading.value,
  4617. onClick: vue.withModifiers(submit, ["stop"])
  4618. }, {
  4619. default: vue.withCtx(() => [
  4620. vue.createTextVNode("回复 ")
  4621. ]),
  4622. _: 1
  4623. }, 8, ["disabled", "loading"])
  4624. ])
  4625. ]),
  4626. vue.withDirectives(vue.createElementVNode("div", {
  4627. class: "emoticon-pack",
  4628. ref_key: "emoticonsRef",
  4629. ref: emoticonsRef
  4630. }, [
  4631. vue.createVNode(vue.unref(Icon), {
  4632. icon: "ic:round-close",
  4633. onClick: _cache[4] || (_cache[4] = vue.withModifiers(($event) => isShowEmoticons.value = false, ["stop"]))
  4634. }),
  4635. _hoisted_8$5,
  4636. vue.createElementVNode("div", _hoisted_9$5, [
  4637. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(classicsEmoticons), (item) => {
  4638. return vue.openBlock(), vue.createElementBlock("img", {
  4639. src: getEmojiSrc(item.high),
  4640. referrerpolicy: "no-referrer",
  4641. onClick: vue.withModifiers(($event) => {
  4642. insert(item.name);
  4643. isShowEmoticons.value = false;
  4644. }, ["stop"])
  4645. }, null, 8, _hoisted_10$5);
  4646. }), 256))
  4647. ]),
  4648. vue.createElementVNode("div", _hoisted_11$5, [
  4649. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(emojiEmoticons), (item) => {
  4650. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  4651. vue.createElementVNode("div", _hoisted_12$5, vue.toDisplayString(item.title), 1),
  4652. vue.createElementVNode("div", _hoisted_13$5, [
  4653. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.list, (emoji) => {
  4654. return vue.openBlock(), vue.createElementBlock("span", {
  4655. onClick: vue.withModifiers(($event) => {
  4656. insert(emoji);
  4657. isShowEmoticons.value = false;
  4658. }, ["stop"])
  4659. }, vue.toDisplayString(emoji), 9, _hoisted_14$4);
  4660. }), 256))
  4661. ])
  4662. ], 64);
  4663. }), 256))
  4664. ])
  4665. ], 512), [
  4666. [vue.vShow, isShowEmoticons.value]
  4667. ])
  4668. ], 2);
  4669. };
  4670. }
  4671. };
  4672. const PostEditor = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-85e09b4e"]]);
  4673. const _hoisted_1$b = {
  4674. key: 0,
  4675. class: "html-wrapper"
  4676. };
  4677. const _hoisted_2$8 = ["innerHTML"];
  4678. const checkHeight = 900;
  4679. const _sfc_main$b = {
  4680. __name: "BaseHtmlRender",
  4681. props: ["html"],
  4682. setup(__props) {
  4683. const config2 = vue.inject("config");
  4684. const props = __props;
  4685. const contentRef = vue.ref(null);
  4686. const mask = vue.ref(false);
  4687. const handOpen = vue.ref(false);
  4688. function mouseup(e2) {
  4689. if (!config2.value.base64)
  4690. return;
  4691. let selectionText = window.getSelection().toString();
  4692. if (selectionText) {
  4693. let r2 = selectionText.match(/([A-Za-z0-9+/=]+)/g);
  4694. if (r2) {
  4695. if (r2[0].length < 4)
  4696. return;
  4697. eventBus.emit(CMD.SHOW_TOOLTIP, { text: r2[0], e: e2 });
  4698. }
  4699. }
  4700. }
  4701. vue.watch(config2.value, (newVale) => {
  4702. if (!newVale.contentAutoCollapse) {
  4703. mask.value = false;
  4704. }
  4705. });
  4706. vue.watch([() => contentRef.value, () => props.html], () => {
  4707. if (!contentRef.value || !props.html)
  4708. return;
  4709. if (!config2.value.contentAutoCollapse)
  4710. return;
  4711. contentRef.value.querySelectorAll("img").forEach((item) => {
  4712. item.removeEventListener("load", checkContentHeight);
  4713. item.addEventListener("load", checkContentHeight);
  4714. });
  4715. checkContentHeight();
  4716. }, { immediate: true, flush: "post" });
  4717. function checkContentHeight() {
  4718. if (handOpen.value)
  4719. return;
  4720. if (!contentRef.value)
  4721. return;
  4722. let rect = contentRef.value.getBoundingClientRect();
  4723. mask.value = rect.height >= checkHeight;
  4724. }
  4725. return (_ctx, _cache) => {
  4726. return props.html ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$b, [
  4727. vue.createElementVNode("div", {
  4728. class: vue.normalizeClass({ mask: mask.value })
  4729. }, [
  4730. vue.createElementVNode("div", {
  4731. ref_key: "contentRef",
  4732. ref: contentRef,
  4733. innerHTML: props.html,
  4734. onMouseup: mouseup
  4735. }, null, 40, _hoisted_2$8)
  4736. ], 2),
  4737. mask.value ? (vue.openBlock(), vue.createElementBlock("div", {
  4738. key: 0,
  4739. class: "expand",
  4740. onClick: _cache[0] || (_cache[0] = ($event) => {
  4741. mask.value = false;
  4742. handOpen.value = true;
  4743. })
  4744. }, "展开")) : vue.createCommentVNode("", true)
  4745. ])) : vue.createCommentVNode("", true);
  4746. };
  4747. }
  4748. };
  4749. const BaseHtmlRender = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-6f61a860"]]);
  4750. const _sfc_main$a = {
  4751. name: "TopSubComment",
  4752. components: { BaseHtmlRender, Author, PostEditor, Point, Icon },
  4753. inject: ["post", "postDetailWidth", "show", "isNight", "isLogin", "tags", "config"],
  4754. props: {
  4755. modelValue: {
  4756. reply_content: ""
  4757. },
  4758. level: -1
  4759. },
  4760. data() {
  4761. return {
  4762. expand: true,
  4763. edit: false,
  4764. replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
  4765. floor: this.modelValue.floor
  4766. };
  4767. },
  4768. watch: {
  4769. show(e2) {
  4770. if (e2) {
  4771. this.edit = false;
  4772. }
  4773. }
  4774. },
  4775. computed: {
  4776. myTags() {
  4777. return this.tags[this.modelValue.username] ?? [];
  4778. }
  4779. },
  4780. methods: {
  4781. jump() {
  4782. eventBus.emit(CMD.JUMP, this.modelValue.floor);
  4783. }
  4784. }
  4785. };
  4786. const _withScopeId$7 = (n2) => (vue.pushScopeId("data-v-d3f8c94b"), n2 = n2(), vue.popScopeId(), n2);
  4787. const _hoisted_1$a = ["data-floor"];
  4788. const _hoisted_2$7 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "left expand-line" }, null, -1));
  4789. const _hoisted_3$7 = { class: "right" };
  4790. const _hoisted_4$7 = { class: "simple-wrapper" };
  4791. function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
  4792. const _component_Author = vue.resolveComponent("Author");
  4793. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  4794. const _component_PostEditor = vue.resolveComponent("PostEditor");
  4795. const _component_TopSubComment = vue.resolveComponent("TopSubComment", true);
  4796. return vue.openBlock(), vue.createElementBlock("div", {
  4797. class: vue.normalizeClass(["top-sub-comment", $props.level === 1 && "top-sub-reply"]),
  4798. ref: "comment",
  4799. "data-floor": $data.floor
  4800. }, [
  4801. _hoisted_2$7,
  4802. vue.createElementVNode("div", _hoisted_3$7, [
  4803. vue.createVNode(_component_Author, {
  4804. modelValue: $data.expand,
  4805. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
  4806. comment: $props.modelValue,
  4807. onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
  4808. type: "top"
  4809. }, null, 8, ["modelValue", "comment"]),
  4810. vue.createVNode(_component_BaseHtmlRender, {
  4811. class: "top-reply_content reply_content",
  4812. html: $props.modelValue.hideCallUserReplyContent
  4813. }, null, 8, ["html"]),
  4814. $data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
  4815. key: 0,
  4816. onClose: _cache[2] || (_cache[2] = ($event) => $data.edit = false),
  4817. replyInfo: $data.replyInfo,
  4818. replyUser: $props.modelValue.username,
  4819. replyFloor: $props.modelValue.floor
  4820. }, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true),
  4821. vue.createElementVNode("div", _hoisted_4$7, [
  4822. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index) => {
  4823. return vue.openBlock(), vue.createBlock(_component_TopSubComment, {
  4824. modelValue: $props.modelValue.children[index],
  4825. "onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
  4826. key: index
  4827. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  4828. }), 128))
  4829. ])
  4830. ])
  4831. ], 10, _hoisted_1$a);
  4832. }
  4833. const TopSubComment = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["render", _sfc_render$5], ["__scopeId", "data-v-d3f8c94b"]]);
  4834. const _sfc_main$9 = {
  4835. name: "Comment",
  4836. components: { BaseHtmlRender, Author, PostEditor, Point, Icon, TopSubComment },
  4837. inject: ["post", "postDetailWidth", "show", "isNight", "config"],
  4838. props: {
  4839. modelValue: {
  4840. reply_content: ""
  4841. },
  4842. type: {
  4843. type: String,
  4844. default() {
  4845. return "list";
  4846. }
  4847. }
  4848. },
  4849. data() {
  4850. return {
  4851. edit: false,
  4852. ding: false,
  4853. expand: true,
  4854. expandTopReply: true,
  4855. expandWrong: false,
  4856. replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
  4857. cssStyle: null,
  4858. floor: this.modelValue.floor
  4859. };
  4860. },
  4861. watch: {
  4862. show(e2) {
  4863. if (e2) {
  4864. this.edit = false;
  4865. }
  4866. },
  4867. postDetailWidth(n2, o) {
  4868. this.checkIsTooLong(n2);
  4869. }
  4870. },
  4871. computed: {
  4872. CommentDisplayType() {
  4873. return CommentDisplayType;
  4874. },
  4875. myClass() {
  4876. return {
  4877. isOp: this.modelValue.isOp,
  4878. isSimple: this.config.viewType === "simple",
  4879. ding: this.ding,
  4880. isLevelOne: this.type === "top" ? true : this.modelValue.level === 0,
  4881. ["c_" + this.floor]: this.type !== "top"
  4882. };
  4883. }
  4884. },
  4885. mounted() {
  4886. this.checkIsTooLong(this.postDetailWidth);
  4887. },
  4888. methods: {
  4889. checkIsTooLong(postDetailWidth) {
  4890. if (postDetailWidth !== 0) {
  4891. let rect = this.$refs.comment.getBoundingClientRect();
  4892. let ban = postDetailWidth * 0.6;
  4893. if (ban < rect.width && rect.width < ban + 25 && this.modelValue.children.length) {
  4894. this.expand = false;
  4895. let padding = 2;
  4896. this.cssStyle = {
  4897. padding: "1rem 0",
  4898. width: `calc(${postDetailWidth}px - ${padding}rem)`,
  4899. transform: `translateX(calc(${rect.width - postDetailWidth}px + ${padding}rem))`,
  4900. background: this.isNight ? "#18222d" : "white"
  4901. };
  4902. }
  4903. }
  4904. },
  4905. //高亮一下
  4906. showDing() {
  4907. this.ding = true;
  4908. setTimeout(() => {
  4909. this.ding = false;
  4910. }, 2e3);
  4911. },
  4912. hide() {
  4913. let url = `${location.origin}/ignore/reply/${this.modelValue.id}?once=${this.post.once}`;
  4914. eventBus.emit(CMD.REMOVE, this.modelValue.floor);
  4915. $.post(url).then((res) => {
  4916. eventBus.emit(CMD.REFRESH_ONCE);
  4917. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "隐藏成功" });
  4918. }, (err) => {
  4919. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "隐藏成功,仅本次有效(接口调用失败!)" });
  4920. });
  4921. },
  4922. toggle() {
  4923. this.expand = !this.expand;
  4924. },
  4925. jump() {
  4926. eventBus.emit(CMD.JUMP, this.modelValue.floor);
  4927. }
  4928. }
  4929. };
  4930. const _withScopeId$6 = (n2) => (vue.pushScopeId("data-v-984ba483"), n2 = n2(), vue.popScopeId(), n2);
  4931. const _hoisted_1$9 = ["data-floor"];
  4932. const _hoisted_2$6 = { class: "comment-content" };
  4933. const _hoisted_3$6 = { class: "right" };
  4934. const _hoisted_4$6 = { class: "w" };
  4935. const _hoisted_5$5 = {
  4936. key: 0,
  4937. class: "wrong-wrapper"
  4938. };
  4939. const _hoisted_6$5 = ["href"];
  4940. const _hoisted_7$4 = { class: "del-line" };
  4941. const _hoisted_8$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("i", {
  4942. class: "fa fa-question-circle-o wrong-icon",
  4943. "aria-hidden": "true"
  4944. }, null, -1));
  4945. const _hoisted_9$4 = {
  4946. key: 0,
  4947. class: "warning"
  4948. };
  4949. const _hoisted_10$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4950. const _hoisted_11$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4951. const _hoisted_12$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4952. const _hoisted_13$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4953. const _hoisted_14$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4954. const _hoisted_15$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("a", {
  4955. href: "https://github.com/zyronon/V2Next/issues",
  4956. target: "_blank"
  4957. }, "这里", -1));
  4958. const _hoisted_16$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "gang" }, null, -1));
  4959. const _hoisted_17$3 = { class: "simple-wrapper" };
  4960. const _hoisted_18$3 = {
  4961. key: 0,
  4962. class: "top-reply-wrap"
  4963. };
  4964. function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
  4965. const _component_Author = vue.resolveComponent("Author");
  4966. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  4967. const _component_PostEditor = vue.resolveComponent("PostEditor");
  4968. const _component_Icon = vue.resolveComponent("Icon");
  4969. const _component_TopSubComment = vue.resolveComponent("TopSubComment");
  4970. const _component_Comment = vue.resolveComponent("Comment", true);
  4971. return vue.openBlock(), vue.createElementBlock("div", {
  4972. class: vue.normalizeClass(["comment", $options.myClass]),
  4973. ref: "comment",
  4974. "data-floor": $data.floor
  4975. }, [
  4976. vue.createVNode(_component_Author, {
  4977. modelValue: $data.expand,
  4978. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
  4979. comment: $props.modelValue,
  4980. onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
  4981. type: $props.type,
  4982. onHide: $options.hide
  4983. }, null, 8, ["modelValue", "comment", "type", "onHide"]),
  4984. $data.cssStyle && !$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  4985. key: 0,
  4986. class: "more ago",
  4987. onClick: _cache[2] || (_cache[2] = ($event) => $data.expand = !$data.expand)
  4988. }, " 由于嵌套回复层级太深,自动将后续回复隐藏 ")) : vue.createCommentVNode("", true),
  4989. $data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  4990. key: 1,
  4991. class: "comment-content-w",
  4992. style: vue.normalizeStyle($data.cssStyle)
  4993. }, [
  4994. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  4995. key: 0,
  4996. class: "more ago",
  4997. onClick: _cache[3] || (_cache[3] = ($event) => $data.expand = !$data.expand)
  4998. }, " 由于嵌套回复层级太深,自动将以下回复移至可见范围 ")) : vue.createCommentVNode("", true),
  4999. vue.createElementVNode("div", _hoisted_2$6, [
  5000. vue.createElementVNode("div", {
  5001. class: "left expand-line",
  5002. onClick: _cache[4] || (_cache[4] = (...args) => $options.toggle && $options.toggle(...args))
  5003. }),
  5004. vue.createElementVNode("div", _hoisted_3$6, [
  5005. vue.createElementVNode("div", _hoisted_4$6, [
  5006. $props.modelValue.isWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$5, [
  5007. vue.createElementVNode("span", {
  5008. onClick: _cache[5] || (_cache[5] = ($event) => $data.expandWrong = !$data.expandWrong),
  5009. title: "点击楼层号查看提示"
  5010. }, [
  5011. vue.createElementVNode("a", {
  5012. href: "/member/" + $props.modelValue.replyUsers[0]
  5013. }, "@" + vue.toDisplayString($props.modelValue.replyUsers[0]) + "  ", 9, _hoisted_6$5),
  5014. vue.createElementVNode("span", _hoisted_7$4, "#" + vue.toDisplayString($props.modelValue.replyFloor), 1),
  5015. _hoisted_8$4
  5016. ]),
  5017. $data.expandWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$4, [
  5018. vue.createTextVNode(" 这条回复似乎有点问题,指定的楼层号与@的人对应不上 "),
  5019. _hoisted_10$4,
  5020. vue.createTextVNode(" 原因可能有下面几种: "),
  5021. _hoisted_11$4,
  5022. vue.createTextVNode(" 一、屏蔽用户导致楼层塌陷:你屏蔽了A,自A以后的回复的楼层号都会减1 "),
  5023. _hoisted_12$4,
  5024. vue.createTextVNode(" 二、忽略回复导致楼层塌陷:原理同上 "),
  5025. _hoisted_13$4,
  5026. vue.createTextVNode(" 三、层主回复时指定错了楼层号(同一,层主屏蔽了别人,导致楼层塌陷) "),
  5027. _hoisted_14$3,
  5028. vue.createTextVNode(" 四、脚本解析错误,请在 "),
  5029. _hoisted_15$3,
  5030. vue.createTextVNode("反馈 ")
  5031. ])) : vue.createCommentVNode("", true)
  5032. ])) : vue.createCommentVNode("", true),
  5033. [$options.CommentDisplayType.Like, $options.CommentDisplayType.FloorInFloorNoCallUser].includes($options.config.commentDisplayType) && $props.type !== "top" ? (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  5034. key: 1,
  5035. class: "reply_content",
  5036. html: $props.modelValue.hideCallUserReplyContent
  5037. }, null, 8, ["html"])) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  5038. key: 2,
  5039. class: "reply_content",
  5040. html: $props.modelValue.reply_content
  5041. }, null, 8, ["html"])),
  5042. $data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
  5043. key: 3,
  5044. onClose: _cache[6] || (_cache[6] = ($event) => $data.edit = false),
  5045. replyInfo: $data.replyInfo,
  5046. replyUser: $props.modelValue.username,
  5047. replyFloor: $props.modelValue.floor
  5048. }, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true),
  5049. $props.type === "top" && $props.modelValue.replyCount ? (vue.openBlock(), vue.createElementBlock("div", {
  5050. key: 4,
  5051. class: "reply-count",
  5052. onClick: _cache[7] || (_cache[7] = ($event) => $data.expandTopReply = !$data.expandTopReply)
  5053. }, [
  5054. _hoisted_16$3,
  5055. vue.createElementVNode("span", null, " 共有" + vue.toDisplayString($props.modelValue.replyCount) + " 条回复 ", 1),
  5056. $data.expandTopReply ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  5057. key: 0,
  5058. icon: "ep:arrow-up-bold"
  5059. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  5060. key: 1,
  5061. icon: "ep:arrow-down-bold"
  5062. }))
  5063. ])) : vue.createCommentVNode("", true)
  5064. ]),
  5065. vue.createElementVNode("div", _hoisted_17$3, [
  5066. $props.type === "top" ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  5067. $data.expandTopReply && $props.modelValue.replyCount ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18$3, [
  5068. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index) => {
  5069. return vue.openBlock(), vue.createBlock(_component_TopSubComment, {
  5070. level: 1,
  5071. modelValue: $props.modelValue.children[index],
  5072. "onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
  5073. key: index
  5074. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  5075. }), 128))
  5076. ])) : vue.createCommentVNode("", true)
  5077. ], 64)) : (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList($props.modelValue.children, (item, index) => {
  5078. return vue.openBlock(), vue.createBlock(_component_Comment, {
  5079. modelValue: $props.modelValue.children[index],
  5080. "onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
  5081. key: index
  5082. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  5083. }), 128))
  5084. ])
  5085. ])
  5086. ]),
  5087. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  5088. key: 1,
  5089. class: "more ago",
  5090. onClick: _cache[8] || (_cache[8] = ($event) => $data.expand = !$data.expand)
  5091. }, " 由于嵌套回复层级太深,自动将以上回复移至可见范围 ")) : vue.createCommentVNode("", true)
  5092. ], 4)) : vue.createCommentVNode("", true)
  5093. ], 10, _hoisted_1$9);
  5094. }
  5095. const Comment = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$4], ["__scopeId", "data-v-984ba483"]]);
  5096. const _sfc_main$8 = {
  5097. name: "Toolbar",
  5098. components: { Icon, BaseLoading },
  5099. inject: [
  5100. "isLogin",
  5101. "post",
  5102. "pageType"
  5103. ],
  5104. data() {
  5105. return {
  5106. timer: null,
  5107. loading: false,
  5108. loading2: false,
  5109. loading3: false
  5110. };
  5111. },
  5112. methods: {
  5113. checkIsLogin(emitName = "") {
  5114. if (!this.isLogin) {
  5115. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  5116. return false;
  5117. }
  5118. this.$emit(emitName);
  5119. return true;
  5120. },
  5121. tweet() {
  5122. var _a;
  5123. let username = ((_a = window.user) == null ? void 0 : _a.username) ?? "";
  5124. let url = `https://twitter.com/intent/tweet?url=${location.origin}/t/${this.post.id}?r=${username}&related=v2ex&text=${this.post.title}`;
  5125. window.open(url, "_blank", "width=550,height=370");
  5126. },
  5127. async report() {
  5128. if (!this.checkIsLogin())
  5129. return;
  5130. if (this.loading3)
  5131. return;
  5132. let isReport = this.post.isReport;
  5133. if (isReport) {
  5134. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
  5135. return;
  5136. }
  5137. let url = `${location.origin}/report/topic/${this.post.id}?once=${this.post.once}`;
  5138. this.loading3 = true;
  5139. let apiRes = await fetch(url);
  5140. this.loading3 = false;
  5141. if (apiRes.redirected) {
  5142. let htmlText = await apiRes.text();
  5143. if (htmlText.search("你已对本主题进行了报告")) {
  5144. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
  5145. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  5146. eventBus.emit(CMD.MERGE, { isReport: !isReport });
  5147. return;
  5148. }
  5149. }
  5150. eventBus.emit(CMD.REFRESH_ONCE);
  5151. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败,请重试" });
  5152. },
  5153. async toggleIgnore() {
  5154. if (!this.checkIsLogin())
  5155. return;
  5156. let url = `${location.origin}/${this.post.isIgnore ? "unignore" : "ignore"}/topic/${this.post.id}?once=${this.post.once}`;
  5157. if (this.pageType === PageType.Post) {
  5158. this.loading2 = true;
  5159. let apiRes = await fetch(url);
  5160. if (apiRes.redirected) {
  5161. if (!this.post.isIgnore) {
  5162. window.location = location.origin;
  5163. }
  5164. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  5165. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  5166. } else {
  5167. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略失败" });
  5168. }
  5169. this.loading2 = false;
  5170. } else {
  5171. if (this.post.isIgnore) {
  5172. this.loading2 = true;
  5173. } else {
  5174. eventBus.emit(CMD.IGNORE);
  5175. }
  5176. let apiRes = await fetch(url);
  5177. if (apiRes.redirected) {
  5178. if (this.post.isIgnore) {
  5179. eventBus.emit(CMD.REFRESH_ONCE);
  5180. }
  5181. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  5182. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  5183. } else {
  5184. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略成功,仅本次有效(接口调用失败!)" });
  5185. }
  5186. this.loading2 = false;
  5187. }
  5188. },
  5189. async toggleFavorite() {
  5190. if (!this.checkIsLogin())
  5191. return;
  5192. if (this.loading)
  5193. return;
  5194. let isFavorite = this.post.isFavorite;
  5195. if (!isFavorite && config.collectBrowserNotice) {
  5196. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "别忘记按Command/Cmd/CTRL + D添加到书签哦" });
  5197. }
  5198. let url = `${location.origin}/${isFavorite ? "unfavorite" : "favorite"}/topic/${this.post.id}?once=${this.post.once}`;
  5199. this.loading = true;
  5200. let apiRes = await fetch(url);
  5201. this.loading = false;
  5202. if (apiRes.redirected) {
  5203. let htmlText = await apiRes.text();
  5204. if (htmlText.search(isFavorite ? "加入收藏" : "取消收藏")) {
  5205. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: isFavorite ? "取消成功" : "收藏成功" });
  5206. eventBus.emit(CMD.MERGE, { collectCount: isFavorite ? this.post.collectCount - 1 : this.post.collectCount + 1 });
  5207. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  5208. eventBus.emit(CMD.MERGE, { isFavorite: !isFavorite });
  5209. return;
  5210. }
  5211. }
  5212. eventBus.emit(CMD.REFRESH_ONCE);
  5213. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败" });
  5214. }
  5215. }
  5216. };
  5217. const _withScopeId$5 = (n2) => (vue.pushScopeId("data-v-30dac564"), n2 = n2(), vue.popScopeId(), n2);
  5218. const _hoisted_1$8 = { class: "toolbar" };
  5219. const _hoisted_2$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复", -1));
  5220. const _hoisted_3$5 = {
  5221. key: 0,
  5222. class: "tool no-hover"
  5223. };
  5224. const _hoisted_4$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "Tweet", -1));
  5225. function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
  5226. const _component_Icon = vue.resolveComponent("Icon");
  5227. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  5228. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
  5229. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true),
  5230. vue.createElementVNode("div", {
  5231. class: "tool",
  5232. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => $options.checkIsLogin("reply"), ["stop"]))
  5233. }, [
  5234. vue.createVNode(_component_Icon, { icon: "mynaui:message" }),
  5235. _hoisted_2$5
  5236. ]),
  5237. vue.createElementVNode("div", {
  5238. class: vue.normalizeClass(["tool", { disabled: $data.loading }]),
  5239. onClick: _cache[1] || (_cache[1] = vue.withModifiers((...args) => $options.toggleFavorite && $options.toggleFavorite(...args), ["stop"]))
  5240. }, [
  5241. $data.loading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  5242. key: 0,
  5243. size: "small"
  5244. })) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  5245. $options.post.isFavorite ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  5246. key: 0,
  5247. color: "rgb(224,42,42)",
  5248. icon: "iconoir:star-solid"
  5249. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  5250. key: 1,
  5251. icon: "iconoir:star"
  5252. }))
  5253. ], 64)),
  5254. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isFavorite ? "取消" : "") + "收藏", 1)
  5255. ], 2),
  5256. $options.post.collectCount !== 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$5, [
  5257. vue.createElementVNode("span", null, vue.toDisplayString($options.post.collectCount + "人收藏"), 1)
  5258. ])) : vue.createCommentVNode("", true),
  5259. vue.createElementVNode("div", {
  5260. class: "tool",
  5261. onClick: _cache[2] || (_cache[2] = vue.withModifiers((...args) => $options.tweet && $options.tweet(...args), ["stop"]))
  5262. }, [
  5263. vue.createVNode(_component_Icon, { icon: "uil:share" }),
  5264. _hoisted_4$5
  5265. ]),
  5266. vue.createElementVNode("div", {
  5267. class: vue.normalizeClass(["tool", { "disabled": $data.loading2 }]),
  5268. onClick: _cache[3] || (_cache[3] = vue.withModifiers((...args) => $options.toggleIgnore && $options.toggleIgnore(...args), ["stop"]))
  5269. }, [
  5270. $data.loading2 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  5271. key: 0,
  5272. size: "small"
  5273. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  5274. key: 1,
  5275. icon: "fluent:eye-hide-24-regular"
  5276. })),
  5277. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isIgnore ? "取消忽略" : "忽略"), 1)
  5278. ], 2),
  5279. vue.createElementVNode("div", {
  5280. class: vue.normalizeClass(["tool", { "disabled": $data.loading3 }]),
  5281. onClick: _cache[4] || (_cache[4] = vue.withModifiers((...args) => $options.report && $options.report(...args), ["stop"]))
  5282. }, [
  5283. $data.loading3 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  5284. key: 0,
  5285. size: "small"
  5286. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  5287. key: 1,
  5288. class: "black",
  5289. icon: "solar:danger-triangle-outline"
  5290. })),
  5291. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isReport ? "你已对本主题进行了报告" : "报告"), 1)
  5292. ], 2)
  5293. ]);
  5294. }
  5295. const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$3], ["__scopeId", "data-v-30dac564"]]);
  5296. const _withScopeId$4 = (n2) => (vue.pushScopeId("data-v-4a063111"), n2 = n2(), vue.popScopeId(), n2);
  5297. const _hoisted_1$7 = ["href"];
  5298. const _hoisted_2$4 = ["src"];
  5299. const _hoisted_3$4 = { class: "texts" };
  5300. const _hoisted_4$4 = {
  5301. key: 0,
  5302. class: "point"
  5303. };
  5304. const _hoisted_5$4 = { class: "link-num" };
  5305. const _hoisted_6$4 = { class: "my-tag" };
  5306. const _hoisted_7$3 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  5307. const _hoisted_8$3 = {
  5308. key: 2,
  5309. class: "ago"
  5310. };
  5311. const _hoisted_9$3 = {
  5312. key: 3,
  5313. class: "mod"
  5314. };
  5315. const _hoisted_10$3 = {
  5316. key: 4,
  5317. class: "owner"
  5318. };
  5319. const _hoisted_11$3 = ["href"];
  5320. const _hoisted_12$3 = {
  5321. key: 5,
  5322. class: "owner"
  5323. };
  5324. const _hoisted_13$3 = {
  5325. key: 6,
  5326. class: "mod"
  5327. };
  5328. const _hoisted_14$2 = {
  5329. key: 7,
  5330. class: "ago"
  5331. };
  5332. const _hoisted_15$2 = { class: "my-tag" };
  5333. const _hoisted_16$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  5334. const _hoisted_17$2 = {
  5335. key: 9,
  5336. class: "point"
  5337. };
  5338. const _hoisted_18$2 = { class: "link-num" };
  5339. const _hoisted_19$2 = ["href"];
  5340. const _hoisted_20$2 = ["src"];
  5341. const _hoisted_21$2 = { class: "Author-right" };
  5342. const _hoisted_22$2 = { class: "floor" };
  5343. const _hoisted_23$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  5344. const _hoisted_24$1 = [
  5345. _hoisted_23$2
  5346. ];
  5347. const _sfc_main$7 = {
  5348. __name: "SingleComment",
  5349. props: {
  5350. comment: {
  5351. reply_content: ""
  5352. },
  5353. isRight: {
  5354. type: Boolean,
  5355. default() {
  5356. return false;
  5357. }
  5358. }
  5359. },
  5360. setup(__props) {
  5361. const config2 = vue.inject("config");
  5362. const isLogin = vue.inject("isLogin");
  5363. const tags = vue.inject("tags");
  5364. const props = __props;
  5365. const myTags = vue.computed(() => {
  5366. return tags[props.comment.username] ?? [];
  5367. });
  5368. function jump() {
  5369. eventBus.emit(CMD.JUMP, props.comment.floor);
  5370. }
  5371. return (_ctx, _cache) => {
  5372. return vue.openBlock(), vue.createElementBlock("div", {
  5373. class: vue.normalizeClass(["comment", { isSimple: vue.unref(config2).viewType === "simple" }]),
  5374. ref: "comment"
  5375. }, [
  5376. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  5377. key: 0,
  5378. class: "avatar",
  5379. href: `/member/${__props.comment.username}`
  5380. }, [
  5381. vue.createElementVNode("img", {
  5382. src: __props.comment.avatar,
  5383. alt: ""
  5384. }, null, 8, _hoisted_2$4)
  5385. ], 8, _hoisted_1$7)) : vue.createCommentVNode("", true),
  5386. vue.createElementVNode("div", {
  5387. class: vue.normalizeClass(["comment-body", { isRight: __props.isRight }])
  5388. }, [
  5389. vue.createElementVNode("div", _hoisted_3$4, [
  5390. __props.comment.thankCount && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, [
  5391. __props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  5392. key: 0,
  5393. color: "rgb(224,42,42)",
  5394. icon: "icon-park-solid:like"
  5395. })) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  5396. key: 1,
  5397. color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
  5398. icon: "icon-park-outline:like"
  5399. }, null, 8, ["color"])),
  5400. vue.createElementVNode("div", _hoisted_5$4, vue.toDisplayString(__props.comment.thankCount), 1)
  5401. ])) : vue.createCommentVNode("", true),
  5402. vue.unref(isLogin) && vue.unref(config2).openTag && __props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(myTags.value, (i) => {
  5403. return vue.openBlock(), vue.createElementBlock("span", _hoisted_6$4, [
  5404. _hoisted_7$3,
  5405. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  5406. ]);
  5407. }), 256)) : vue.createCommentVNode("", true),
  5408. __props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_8$3, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  5409. __props.comment.isMod && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$3, "MOD")) : vue.createCommentVNode("", true),
  5410. __props.comment.isOp && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$3, "OP")) : vue.createCommentVNode("", true),
  5411. vue.createElementVNode("a", {
  5412. href: `/member/${__props.comment.username}`,
  5413. class: "username"
  5414. }, vue.toDisplayString(__props.comment.username), 9, _hoisted_11$3),
  5415. __props.comment.isOp && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$3, "OP")) : vue.createCommentVNode("", true),
  5416. __props.comment.isMod && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$3, "MOD")) : vue.createCommentVNode("", true),
  5417. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_14$2, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  5418. vue.unref(isLogin) && vue.unref(config2).openTag && !__props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 8 }, vue.renderList(myTags.value, (i) => {
  5419. return vue.openBlock(), vue.createElementBlock("span", _hoisted_15$2, [
  5420. _hoisted_16$2,
  5421. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  5422. ]);
  5423. }), 256)) : vue.createCommentVNode("", true),
  5424. __props.comment.thankCount && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_17$2, [
  5425. __props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  5426. key: 0,
  5427. color: "rgb(224,42,42)",
  5428. icon: "icon-park-solid:like"
  5429. })) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  5430. key: 1,
  5431. color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
  5432. icon: "icon-park-outline:like"
  5433. }, null, 8, ["color"])),
  5434. vue.createElementVNode("div", _hoisted_18$2, vue.toDisplayString(__props.comment.thankCount), 1)
  5435. ])) : vue.createCommentVNode("", true)
  5436. ]),
  5437. vue.createVNode(BaseHtmlRender, {
  5438. class: "reply_content",
  5439. html: __props.comment.reply_content
  5440. }, null, 8, ["html"])
  5441. ], 2),
  5442. __props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  5443. key: 1,
  5444. class: "avatar",
  5445. href: `/member/${__props.comment.username}`
  5446. }, [
  5447. vue.createElementVNode("img", {
  5448. src: __props.comment.avatar,
  5449. alt: ""
  5450. }, null, 8, _hoisted_20$2)
  5451. ], 8, _hoisted_19$2)) : vue.createCommentVNode("", true),
  5452. vue.createElementVNode("div", _hoisted_21$2, [
  5453. vue.createElementVNode("div", _hoisted_22$2, vue.toDisplayString(__props.comment.floor), 1),
  5454. vue.createElementVNode("div", {
  5455. class: "tool jump",
  5456. onClick: vue.withModifiers(jump, ["stop"])
  5457. }, _hoisted_24$1)
  5458. ])
  5459. ], 2);
  5460. };
  5461. }
  5462. };
  5463. const SingleComment = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-4a063111"]]);
  5464. function _css(el, key, value) {
  5465. const reg = /^-?\d+.?\d*(px|pt|em|rem|vw|vh|%|rpx|ms)$/i;
  5466. if (value === void 0) {
  5467. let val = null;
  5468. if ("getComputedStyle" in window) {
  5469. val = window.getComputedStyle(el, null)[key];
  5470. } else {
  5471. val = el.currentStyle[key];
  5472. }
  5473. return reg.test(val) ? parseFloat(val) : val;
  5474. } else {
  5475. if ([
  5476. "top",
  5477. "left",
  5478. "bottom",
  5479. "right",
  5480. "width",
  5481. "height",
  5482. "font-size",
  5483. "margin",
  5484. "padding"
  5485. ].includes(key)) {
  5486. if (!reg.test(value)) {
  5487. if (!String(value).includes("calc")) {
  5488. value += "px";
  5489. }
  5490. }
  5491. }
  5492. if (key === "transform") {
  5493. el.style.webkitTransform = el.style.MsTransform = el.style.msTransform = el.style.MozTransform = el.style.OTransform = el.style.transform = value;
  5494. } else {
  5495. el.style[key] = value;
  5496. }
  5497. }
  5498. }
  5499. function getImgSize(naturalWidth, naturalHeight, maxWidth, maxHeight) {
  5500. const imgRatio = naturalWidth / naturalHeight;
  5501. const maxRatio = maxWidth / maxHeight;
  5502. let width, height;
  5503. if (imgRatio >= maxRatio) {
  5504. if (naturalWidth > maxWidth) {
  5505. width = maxWidth;
  5506. height = maxWidth / naturalWidth * naturalHeight;
  5507. } else {
  5508. width = naturalWidth;
  5509. height = naturalHeight;
  5510. }
  5511. } else {
  5512. if (naturalHeight > maxHeight) {
  5513. width = maxHeight / naturalHeight * naturalWidth;
  5514. height = maxHeight;
  5515. } else {
  5516. width = naturalWidth;
  5517. height = naturalHeight;
  5518. }
  5519. }
  5520. if (height === 0) {
  5521. height = maxHeight;
  5522. width = height * 1.3;
  5523. } else {
  5524. if (height < 24) {
  5525. height = 50;
  5526. width = height * imgRatio;
  5527. } else if (height < 100) {
  5528. height = 300;
  5529. width = height * imgRatio;
  5530. } else {
  5531. height = maxHeight;
  5532. width = height * imgRatio;
  5533. }
  5534. if (width > maxWidth) {
  5535. width = maxWidth;
  5536. height = width / imgRatio;
  5537. }
  5538. }
  5539. console.log(width, height);
  5540. return { width, height };
  5541. }
  5542. const _sfc_main$6 = {
  5543. name: "detail",
  5544. components: {
  5545. BaseSelect,
  5546. BaseButton,
  5547. SingleComment,
  5548. PopConfirm,
  5549. Comment,
  5550. PostEditor,
  5551. Point,
  5552. Toolbar,
  5553. BaseHtmlRender,
  5554. Tooltip,
  5555. BaseLoading,
  5556. Icon
  5557. },
  5558. inject: ["allReplyUsers", "post", "tags", "isLogin", "config", "pageType", "isNight"],
  5559. provide() {
  5560. return {
  5561. postDetailWidth: vue.computed(() => this.postDetailWidth)
  5562. };
  5563. },
  5564. props: {
  5565. modelValue: {
  5566. type: Boolean,
  5567. default() {
  5568. return false;
  5569. }
  5570. },
  5571. loading: {
  5572. type: Boolean,
  5573. default() {
  5574. return false;
  5575. }
  5576. },
  5577. refreshLoading: {
  5578. type: Boolean,
  5579. default() {
  5580. return false;
  5581. }
  5582. },
  5583. displayType: CommentDisplayType.FloorInFloorNoCallUser
  5584. },
  5585. data() {
  5586. return {
  5587. isSticky: false,
  5588. selectCallIndex: 0,
  5589. postDetailWidth: 0,
  5590. showCallList: false,
  5591. showRelationReply: false,
  5592. replyText: "",
  5593. callStyle: {
  5594. top: 0,
  5595. left: 0
  5596. },
  5597. targetUser: {
  5598. left: [],
  5599. right: "",
  5600. rightFloor: -1
  5601. },
  5602. currentFloor: "",
  5603. showOpTag: false,
  5604. rect: {},
  5605. result: {},
  5606. x: 0,
  5607. y: 0,
  5608. scale: 1,
  5609. minScale: 0.2,
  5610. maxScale: 16,
  5611. preview: {
  5612. rect: {},
  5613. result: {},
  5614. x: 0,
  5615. y: 0,
  5616. scale: 1,
  5617. minScale: 0.2,
  5618. maxScale: 16
  5619. }
  5620. };
  5621. },
  5622. computed: {
  5623. functions() {
  5624. return functions;
  5625. },
  5626. //wow区和东京区的css要特定
  5627. isSpecificArea() {
  5628. if ([PageType.Node, PageType.Post].includes(this.pageType)) {
  5629. if (["东京", "World of Warcraft"].includes(this.post.node.title)) {
  5630. return true;
  5631. }
  5632. }
  5633. return false;
  5634. },
  5635. canAppend() {
  5636. if (this.isMy) {
  5637. let create = new Date(this.post.createDate);
  5638. return Date.now() - create.valueOf() > 1e3 * 60 * 30;
  5639. }
  5640. return false;
  5641. },
  5642. canEditMove() {
  5643. if (this.isMy) {
  5644. let create = new Date(this.post.createDate);
  5645. return Date.now() - create.valueOf() < 1e3 * 60 * 10;
  5646. }
  5647. return false;
  5648. },
  5649. isMy() {
  5650. return this.post.member.username === window.user.username;
  5651. },
  5652. myTags() {
  5653. return this.tags[this.post.member.username] ?? [];
  5654. },
  5655. CommentDisplayType() {
  5656. return CommentDisplayType;
  5657. },
  5658. isPost() {
  5659. return this.pageType === PageType.Post;
  5660. },
  5661. filterCallList() {
  5662. if (this.showCallList) {
  5663. let list = ["管理员", "所有人"].concat(this.allReplyUsers);
  5664. if (this.replyText)
  5665. return list.filter((i) => i.search(this.replyText) > -1);
  5666. return list;
  5667. }
  5668. return [];
  5669. },
  5670. replyList() {
  5671. if ([CommentDisplayType.FloorInFloor, CommentDisplayType.FloorInFloorNoCallUser].includes(this.displayType))
  5672. return this.post.nestedReplies;
  5673. if (this.displayType === CommentDisplayType.Like) {
  5674. return functions.clone(this.post.nestedReplies).sort((a, b) => b.thankCount - a.thankCount);
  5675. }
  5676. if (this.displayType === CommentDisplayType.New) {
  5677. return functions.clone(this.post.replyList).reverse();
  5678. }
  5679. if (this.displayType === CommentDisplayType.V2exOrigin)
  5680. return this.post.replyList;
  5681. if (this.displayType === CommentDisplayType.FloorInFloorNested)
  5682. return this.post.nestedRedundReplies;
  5683. if (this.displayType === CommentDisplayType.OnlyOp)
  5684. return this.post.replyList.filter((v) => {
  5685. var _a;
  5686. return v.username === ((_a = this.post.member) == null ? void 0 : _a.username);
  5687. });
  5688. return [];
  5689. },
  5690. //关联回复
  5691. relationReply() {
  5692. if (this.targetUser.left.length && this.targetUser.right) {
  5693. return this.post.replyList.filter((v) => {
  5694. if (this.targetUser.left.concat(this.targetUser.right).includes(v.username)) {
  5695. if (v.floor > this.targetUser.rightFloor) {
  5696. if (v.replyUsers.includes(this.targetUser.right)) {
  5697. return true;
  5698. }
  5699. if (v.username === this.targetUser.right) {
  5700. for (let i = 0; i < this.targetUser.left.length; i++) {
  5701. if (v.replyUsers.includes(this.targetUser.left[i])) {
  5702. return true;
  5703. }
  5704. }
  5705. }
  5706. } else {
  5707. return true;
  5708. }
  5709. }
  5710. return false;
  5711. });
  5712. }
  5713. return [];
  5714. }
  5715. },
  5716. watch: {
  5717. "post.id"(n2, o) {
  5718. if (this.$refs["post-editor"]) {
  5719. this.$refs["post-editor"].content = "";
  5720. vue.nextTick(() => {
  5721. var _a, _b;
  5722. (_b = (_a = this.$refs) == null ? void 0 : _a.detail) == null ? void 0 : _b.scrollTo({ top: 0 });
  5723. });
  5724. }
  5725. },
  5726. "post.headerTemplate"(n2, o) {
  5727. let mountEl = document.querySelector(".main-wrapper .post-wrapper .html-wrapper .header");
  5728. if (mountEl) {
  5729. this.showOpTag = true;
  5730. }
  5731. },
  5732. modelValue: {
  5733. handler(newVal) {
  5734. if (this.isPost)
  5735. return;
  5736. if (newVal) {
  5737. this.currentFloor = "";
  5738. vue.nextTick(() => {
  5739. var _a, _b;
  5740. (_b = (_a = this.$refs) == null ? void 0 : _a.main) == null ? void 0 : _b.focus();
  5741. });
  5742. } else {
  5743. this.isSticky = false;
  5744. this.showRelationReply = false;
  5745. }
  5746. }
  5747. }
  5748. },
  5749. mounted() {
  5750. vue.nextTick(() => {
  5751. setTimeout(() => {
  5752. var _a;
  5753. this.postDetailWidth = ((_a = this.$refs.mainWrapper) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
  5754. }, 500);
  5755. });
  5756. if (this.isLogin) {
  5757. const observer = new IntersectionObserver(
  5758. ([e2]) => e2.target.toggleAttribute("stuck", e2.intersectionRatio < 1),
  5759. { threshold: [1] }
  5760. );
  5761. observer.observe(this.$refs.replyBox);
  5762. window.addEventListener("keydown", this.onKeyDown);
  5763. }
  5764. eventBus.on(CMD.SHOW_CALL, (val) => {
  5765. if (val.show) {
  5766. this.showCallList = true;
  5767. this.replyText = val.text;
  5768. if (this.isPost) {
  5769. this.callStyle.top = val.top + $(window).scrollTop() + -40 + "px";
  5770. } else {
  5771. this.callStyle.top = val.top + $(".post-detail").scrollTop() + 15 + "px";
  5772. }
  5773. this.callStyle.left = val.left - $(".main")[0].getBoundingClientRect().left + 10 + "px";
  5774. if (this.selectCallIndex >= this.filterCallList.length) {
  5775. this.selectCallIndex = 0;
  5776. }
  5777. } else {
  5778. this.replyText = "";
  5779. this.showCallList = false;
  5780. this.selectCallIndex = 0;
  5781. }
  5782. });
  5783. eventBus.on(CMD.RELATION_REPLY, (val) => {
  5784. this.targetUser = val;
  5785. this.showRelationReply = true;
  5786. });
  5787. eventBus.on(CMD.JUMP, this.jump);
  5788. },
  5789. beforeUnmount() {
  5790. window.removeEventListener("keydown", this.onKeyDown);
  5791. eventBus.off(CMD.SHOW_CALL);
  5792. },
  5793. methods: {
  5794. addTag() {
  5795. eventBus.emit(CMD.ADD_TAG, this.post.member.username);
  5796. },
  5797. removeTag(tag) {
  5798. eventBus.emit(CMD.REMOVE_TAG, { username: this.post.member.username, tag });
  5799. },
  5800. closePreviewModal() {
  5801. let previewModal = document.querySelector(".preview-modal");
  5802. let s = document.querySelector(".shadow");
  5803. let domRect = this.preview.rect;
  5804. _css(s, "transition", "all 0.3s");
  5805. _css(s, "width", domRect.width);
  5806. _css(s, "height", domRect.height);
  5807. _css(s, "transform", `translate3d(${domRect.x}px, ${domRect.y}px, 0) scale(1)`);
  5808. let mask = document.querySelector(".preview-modal .mask");
  5809. _css(mask, "opacity", 0);
  5810. setTimeout(() => {
  5811. _css(s, "transition", "all 0s");
  5812. s.remove();
  5813. _css(previewModal, "top", "-1000vh");
  5814. _css(document.body, "overflow", "auto");
  5815. }, 300);
  5816. },
  5817. stop(e2) {
  5818. e2.stopPropagation();
  5819. e2.stopImmediatePropagation();
  5820. if (e2.target.tagName === "IMG") {
  5821. console.log("e", e2.target.src);
  5822. if (/cdn\.v2ex\.com.*avatar/i.test(e2.target.src)) {
  5823. console.log("t");
  5824. }
  5825. this.preview = {
  5826. rect: {},
  5827. result: {},
  5828. x: 0,
  5829. y: 0,
  5830. scale: 1,
  5831. minScale: 0.2,
  5832. maxScale: 16
  5833. };
  5834. e2.preventDefault();
  5835. let domRect = e2.target.getBoundingClientRect();
  5836. let previewModal = document.querySelector(".preview-modal");
  5837. _css(previewModal, "top", "0");
  5838. let s = e2.target.cloneNode();
  5839. s.classList.add("shadow");
  5840. previewModal.append(s);
  5841. _css(s, "transition", "all 0s");
  5842. _css(s, "width", domRect.width);
  5843. _css(s, "height", domRect.height);
  5844. _css(s, "transform", `translate3d(${domRect.x}px, ${domRect.y}px, 0) scale(1)`);
  5845. let t = ".3";
  5846. let sw = domRect.width / window.innerWidth;
  5847. let sh = domRect.height / window.innerHeight;
  5848. domRect.sw = sw;
  5849. domRect.sh = sh;
  5850. this.preview.rect = domRect;
  5851. this.preview.result = getImgSize(
  5852. s.naturalWidth,
  5853. s.naturalHeight,
  5854. window.innerWidth * 0.95,
  5855. window.innerHeight * 0.9
  5856. );
  5857. this.preview.x = (window.innerWidth - this.preview.result.width) * 0.5;
  5858. this.preview.y = (window.innerHeight - this.preview.result.height) * 0.5;
  5859. let isPointerdown = false;
  5860. let isMove = false;
  5861. let lastPointermove = { x: 0, y: 0 };
  5862. let diff = { x: 0, y: 0 };
  5863. s.addEventListener("pointerdown", function(e3) {
  5864. isPointerdown = true;
  5865. isMove = false;
  5866. s.setPointerCapture(e3.pointerId);
  5867. lastPointermove = { x: e3.clientX, y: e3.clientY };
  5868. });
  5869. s.addEventListener("pointermove", (e3) => {
  5870. if (isPointerdown) {
  5871. isMove = true;
  5872. const current = { x: e3.clientX, y: e3.clientY };
  5873. diff.x = current.x - lastPointermove.x;
  5874. diff.y = current.y - lastPointermove.y;
  5875. lastPointermove = { x: current.x, y: current.y };
  5876. this.preview.x += diff.x;
  5877. this.preview.y += diff.y;
  5878. _css(s, "transition", "all 0.1s");
  5879. _css(s, "transform", `translate3d(${this.preview.x}px, ${this.preview.y}px, 0) scale(${this.preview.scale})`);
  5880. }
  5881. e3.preventDefault();
  5882. });
  5883. s.addEventListener("pointerup", () => {
  5884. if (isPointerdown) {
  5885. isPointerdown = false;
  5886. if (!isMove) {
  5887. this.closePreviewModal();
  5888. }
  5889. }
  5890. });
  5891. s.addEventListener("pointercancel", function(e3) {
  5892. if (isPointerdown) {
  5893. isPointerdown = false;
  5894. }
  5895. });
  5896. let mask = document.querySelector(".preview-modal .mask");
  5897. _css(mask, "transition", "all 0s");
  5898. _css(mask, "opacity", 0);
  5899. setTimeout(() => {
  5900. _css(s, "transition", `all ${t}s`);
  5901. _css(mask, "transition", `all ${t}s`);
  5902. _css(mask, "opacity", 1);
  5903. _css(s, "transform", `translate3d(${this.preview.x}px, ${this.preview.y}px, 0) scale(${this.preview.scale})`);
  5904. _css(s, "width", this.preview.result.width);
  5905. _css(s, "height", this.preview.result.height);
  5906. }, 0);
  5907. setTimeout(() => {
  5908. _css(document.body, "overflow", "hidden");
  5909. }, 300);
  5910. return false;
  5911. }
  5912. },
  5913. wheel(e2) {
  5914. let d2 = e2.deltaY < 0 ? 0.1 : -0.1;
  5915. let ratio = 1 + d2;
  5916. let _scale = this.preview.scale * ratio;
  5917. if (_scale > this.preview.maxScale) {
  5918. ratio = this.preview.maxScale / this.preview.scale;
  5919. this.preview.scale = this.preview.maxScale;
  5920. } else if (_scale < this.preview.minScale) {
  5921. ratio = this.preview.minScale / this.preview.scale;
  5922. this.preview.scale = this.preview.minScale;
  5923. } else {
  5924. this.preview.scale = _scale;
  5925. }
  5926. if (e2.target.tagName === "IMG") {
  5927. const origin = {
  5928. x: d2 * this.preview.result.width / 2,
  5929. y: d2 * this.preview.result.height / 2
  5930. };
  5931. this.preview.x -= d2 * (e2.clientX - this.preview.x) - origin.x;
  5932. this.preview.y -= d2 * (e2.clientY - this.preview.y) - origin.y;
  5933. }
  5934. let s = document.querySelector(".shadow");
  5935. _css(s, "transition", "all 0.2s");
  5936. _css(s, "transform", `translate3d(${this.preview.x}px, ${this.preview.y}px, 0) scale(${this.preview.scale})`);
  5937. e2.preventDefault();
  5938. },
  5939. jump(floor) {
  5940. let lastItem = this.replyList[this.replyList.length - 1];
  5941. if (floor === "") {
  5942. floor = lastItem.floor;
  5943. } else {
  5944. try {
  5945. floor = Number(floor);
  5946. } catch (e2) {
  5947. floor = lastItem.floor;
  5948. }
  5949. if (floor === 0) {
  5950. floor = 1;
  5951. }
  5952. if (floor > lastItem.floor)
  5953. floor = lastItem.floor;
  5954. }
  5955. if (!this.post.replyList.length) {
  5956. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "没有回复可跳转!" });
  5957. return;
  5958. }
  5959. if (floor > this.post.replyList.length) {
  5960. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  5961. return;
  5962. }
  5963. let comment = $(`.c_${floor}`);
  5964. if (!comment.length) {
  5965. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  5966. return;
  5967. }
  5968. comment[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
  5969. comment.addClass("ding");
  5970. this.currentFloor = floor + 1;
  5971. setTimeout(() => {
  5972. comment.removeClass("ding");
  5973. }, 2e3);
  5974. },
  5975. collapseTopReplyList() {
  5976. $(this.$refs.topReply).slideToggle("fast");
  5977. },
  5978. goBottom() {
  5979. this.isSticky = false;
  5980. setTimeout(() => {
  5981. if (this.isPost) {
  5982. let body = $("body , html");
  5983. let scrollHeight = body.prop("scrollHeight");
  5984. body.animate({ scrollTop: scrollHeight - 850 }, 300);
  5985. } else {
  5986. this.$refs.detail.scrollTo({ top: this.$refs.detail.scrollHeight, behavior: "smooth" });
  5987. }
  5988. });
  5989. },
  5990. close(from) {
  5991. if (this.isPost)
  5992. return;
  5993. if (from === "space") {
  5994. if (this.config.closePostDetailBySpace) {
  5995. this.$emit("update:modelValue", false);
  5996. }
  5997. } else {
  5998. this.$emit("update:modelValue", false);
  5999. }
  6000. },
  6001. setCall(e2) {
  6002. eventBus.emit(CMD.SET_CALL, e2);
  6003. this.showCallList = false;
  6004. },
  6005. onKeyDown(e2) {
  6006. if (!this.modelValue)
  6007. return;
  6008. if (!this.showCallList)
  6009. return;
  6010. let length = this.filterCallList.slice(0, 10).length;
  6011. if (e2.keyCode === 13) {
  6012. this.setCall(this.filterCallList[this.selectCallIndex]);
  6013. e2.preventDefault();
  6014. }
  6015. if (e2.keyCode === 38) {
  6016. this.selectCallIndex--;
  6017. if (this.selectCallIndex < 0) {
  6018. this.selectCallIndex = length - 1;
  6019. }
  6020. e2.preventDefault();
  6021. }
  6022. if (e2.keyCode === 40) {
  6023. this.selectCallIndex++;
  6024. if (this.selectCallIndex > length - 1) {
  6025. this.selectCallIndex = 0;
  6026. }
  6027. e2.preventDefault();
  6028. }
  6029. },
  6030. changeOption(item) {
  6031. this.$emit("update:displayType", item);
  6032. },
  6033. addThank() {
  6034. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "add" });
  6035. },
  6036. recallThank() {
  6037. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "recall" });
  6038. },
  6039. scrollTop() {
  6040. if (this.isPost) {
  6041. $("body , html").animate({ scrollTop: 0 }, 300);
  6042. } else {
  6043. this.$refs.detail.scrollTo({ top: 0, behavior: "smooth" });
  6044. }
  6045. }
  6046. }
  6047. };
  6048. const _withScopeId$3 = (n2) => (vue.pushScopeId("data-v-d39217d8"), n2 = n2(), vue.popScopeId(), n2);
  6049. const _hoisted_1$6 = { class: "my-box post-wrapper" };
  6050. const _hoisted_2$3 = { class: "header" };
  6051. const _hoisted_3$3 = { class: "fr" };
  6052. const _hoisted_4$3 = ["href"];
  6053. const _hoisted_5$3 = ["src", "alt"];
  6054. const _hoisted_6$3 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("a", { href: "/" }, "V2EX", -1));
  6055. const _hoisted_7$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "chevron" }, "  ›  ", -1));
  6056. const _hoisted_8$2 = ["href"];
  6057. const _hoisted_9$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep10" }, null, -1));
  6058. const _hoisted_10$2 = ["id"];
  6059. const _hoisted_11$2 = ["onclick"];
  6060. const _hoisted_12$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-up" }, null, -1));
  6061. const _hoisted_13$2 = ["onclick"];
  6062. const _hoisted_14$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-down" }, null, -1));
  6063. const _hoisted_15$1 = [
  6064. _hoisted_14$1
  6065. ];
  6066. const _hoisted_16$1 = { class: "gray" };
  6067. const _hoisted_17$1 = ["href"];
  6068. const _hoisted_18$1 = ["title"];
  6069. const _hoisted_19$1 = ["href"];
  6070. const _hoisted_20$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-info-circle" }, null, -1));
  6071. const _hoisted_21$1 = [
  6072. _hoisted_20$1
  6073. ];
  6074. const _hoisted_22$1 = ["href"];
  6075. const _hoisted_23$1 = ["href"];
  6076. const _hoisted_24 = ["href"];
  6077. const _hoisted_25 = { class: "my-tag" };
  6078. const _hoisted_26 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  6079. const _hoisted_27 = ["onClick"];
  6080. const _hoisted_28 = {
  6081. key: 0,
  6082. class: "my-box"
  6083. };
  6084. const _hoisted_29 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "高赞回复", -1));
  6085. const _hoisted_30 = { class: "top-reply" };
  6086. const _hoisted_31 = { class: "tool" };
  6087. const _hoisted_32 = { ref: "topReply" };
  6088. const _hoisted_33 = { class: "my-box comment-wrapper" };
  6089. const _hoisted_34 = {
  6090. key: 0,
  6091. class: "my-cell flex"
  6092. };
  6093. const _hoisted_35 = { key: 0 };
  6094. const _hoisted_36 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("strong", { class: "snow" }, "•", -1));
  6095. const _hoisted_37 = ["innerHTML"];
  6096. const _hoisted_38 = {
  6097. key: 0,
  6098. class: "loading-wrapper"
  6099. };
  6100. const _hoisted_39 = {
  6101. key: 1,
  6102. class: "comments"
  6103. };
  6104. const _hoisted_40 = {
  6105. key: 1,
  6106. id: "no-comments-yet"
  6107. };
  6108. const _hoisted_41 = { class: "my-cell flex" };
  6109. const _hoisted_42 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "添加一条新回复", -1));
  6110. const _hoisted_43 = { class: "notice-right gray" };
  6111. const _hoisted_44 = { class: "p1" };
  6112. const _hoisted_45 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "上下文", -1));
  6113. const _hoisted_46 = { class: "top-reply" };
  6114. const _hoisted_47 = ["onClick"];
  6115. function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
  6116. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  6117. const _component_Point = vue.resolveComponent("Point");
  6118. const _component_Toolbar = vue.resolveComponent("Toolbar");
  6119. const _component_Icon = vue.resolveComponent("Icon");
  6120. const _component_Tooltip = vue.resolveComponent("Tooltip");
  6121. const _component_Comment = vue.resolveComponent("Comment");
  6122. const _component_BaseSelect = vue.resolveComponent("BaseSelect");
  6123. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  6124. const _component_PostEditor = vue.resolveComponent("PostEditor");
  6125. const _component_SingleComment = vue.resolveComponent("SingleComment");
  6126. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  6127. class: vue.normalizeClass(["post-detail", [$options.isNight ? "isNight" : "", $options.pageType]]),
  6128. ref: "detail",
  6129. onKeydown: _cache[22] || (_cache[22] = vue.withKeys(($event) => $options.close(), ["esc"])),
  6130. onClick: _cache[23] || (_cache[23] = ($event) => $options.close("space"))
  6131. }, [
  6132. vue.createElementVNode("div", {
  6133. ref: "main",
  6134. class: vue.normalizeClass(["main", $options.isSpecificArea ? "specific-area" : ""]),
  6135. tabindex: "1",
  6136. onClick: _cache[19] || (_cache[19] = (...args) => $options.stop && $options.stop(...args))
  6137. }, [
  6138. vue.createElementVNode("div", {
  6139. class: "main-wrapper",
  6140. ref: "mainWrapper",
  6141. style: vue.normalizeStyle({ width: $options.config.postWidth + "!important" })
  6142. }, [
  6143. vue.createElementVNode("div", _hoisted_1$6, [
  6144. vue.createElementVNode("div", _hoisted_2$3, [
  6145. vue.createElementVNode("div", _hoisted_3$3, [
  6146. vue.createElementVNode("a", {
  6147. href: `/member/${$options.post.member.username}`,
  6148. style: { "width": "73px", "height": "73px", "display": "inline-block" }
  6149. }, [
  6150. $options.post.member.avatar_large ? (vue.openBlock(), vue.createElementBlock("img", {
  6151. key: 0,
  6152. src: $options.post.member.avatar_large,
  6153. class: "avatar",
  6154. style: { "width": "73px", "height": "73px" },
  6155. border: "0",
  6156. align: "default",
  6157. alt: $options.post.member.username
  6158. }, null, 8, _hoisted_5$3)) : vue.createCommentVNode("", true)
  6159. ], 8, _hoisted_4$3)
  6160. ]),
  6161. _hoisted_6$3,
  6162. _hoisted_7$2,
  6163. vue.createElementVNode("a", {
  6164. href: $options.post.node.url
  6165. }, vue.toDisplayString($options.post.node.title), 9, _hoisted_8$2),
  6166. _hoisted_9$2,
  6167. vue.createElementVNode("h1", null, vue.toDisplayString($options.post.title), 1),
  6168. vue.createElementVNode("div", {
  6169. id: `topic_${$options.post.id}_votes`,
  6170. class: "votes"
  6171. }, [
  6172. vue.createElementVNode("a", {
  6173. href: "javascript:",
  6174. onclick: `upVoteTopic(${$options.post.id});`,
  6175. class: "vote"
  6176. }, [
  6177. _hoisted_12$2,
  6178. vue.createTextVNode("   ")
  6179. ], 8, _hoisted_11$2),
  6180. vue.createTextVNode("   "),
  6181. vue.createElementVNode("a", {
  6182. href: "javascript:",
  6183. onclick: `downVoteTopic(${$options.post.id});`,
  6184. class: "vote"
  6185. }, _hoisted_15$1, 8, _hoisted_13$2)
  6186. ], 8, _hoisted_10$2),
  6187. vue.createTextVNode("   "),
  6188. vue.createElementVNode("small", _hoisted_16$1, [
  6189. vue.createElementVNode("a", {
  6190. href: `/member/${$options.post.member.username}`
  6191. }, vue.toDisplayString($options.post.member.username), 9, _hoisted_17$1),
  6192. vue.createTextVNode(" · "),
  6193. $options.post.member.createDate ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  6194. vue.createElementVNode("span", {
  6195. class: vue.normalizeClass($options.post.member.isNew && "danger")
  6196. }, vue.toDisplayString($options.post.member.createDate), 3),
  6197. vue.createTextVNode(" · ")
  6198. ], 64)) : vue.createCommentVNode("", true),
  6199. $options.post.createDateAgo ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  6200. vue.createElementVNode("span", {
  6201. title: $options.post.createDate
  6202. }, vue.toDisplayString($options.post.createDateAgo), 9, _hoisted_18$1),
  6203. vue.createTextVNode(" · ")
  6204. ], 64)) : vue.createCommentVNode("", true),
  6205. vue.createTextVNode(" " + vue.toDisplayString($options.post.clickCount) + " 次点击 ", 1),
  6206. $options.isMy ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
  6207. vue.createTextVNode("   "),
  6208. vue.createElementVNode("a", {
  6209. href: `/t/${$options.post.id}/info`
  6210. }, _hoisted_21$1, 8, _hoisted_19$1),
  6211. vue.createTextVNode("   "),
  6212. $options.canAppend ? (vue.openBlock(), vue.createElementBlock("a", {
  6213. key: 0,
  6214. href: `/append/topic/${$options.post.id}`,
  6215. class: "op"
  6216. }, "APPEND", 8, _hoisted_22$1)) : vue.createCommentVNode("", true),
  6217. $options.canEditMove ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  6218. vue.createElementVNode("a", {
  6219. href: `/move/topic/${$options.post.id}`,
  6220. class: "op"
  6221. }, "MOVE", 8, _hoisted_23$1),
  6222. vue.createTextVNode("  "),
  6223. vue.createElementVNode("a", {
  6224. href: `/edit/topic/${$options.post.id}`,
  6225. class: "op"
  6226. }, "EDIT", 8, _hoisted_24)
  6227. ], 64)) : vue.createCommentVNode("", true)
  6228. ], 64)) : vue.createCommentVNode("", true)
  6229. ]),
  6230. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  6231. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  6232. return vue.openBlock(), vue.createElementBlock("span", _hoisted_25, [
  6233. _hoisted_26,
  6234. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  6235. vue.createElementVNode("i", {
  6236. class: "fa fa-trash-o remove",
  6237. onClick: vue.withModifiers(($event) => $options.removeTag(i), ["stop"])
  6238. }, null, 8, _hoisted_27)
  6239. ]);
  6240. }), 256)),
  6241. vue.createElementVNode("span", {
  6242. class: "add-tag ago",
  6243. onClick: _cache[0] || (_cache[0] = vue.withModifiers((...args) => $options.addTag && $options.addTag(...args), ["stop"])),
  6244. title: "添加标签"
  6245. }, "+")
  6246. ], 64)) : vue.createCommentVNode("", true)
  6247. ]),
  6248. $options.post.headerTemplate ? (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  6249. key: 0,
  6250. html: $options.post.headerTemplate
  6251. }, null, 8, ["html"])) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  6252. key: 1,
  6253. html: $options.post.jsonContent
  6254. }, null, 8, ["html"])),
  6255. vue.createVNode(_component_Toolbar, {
  6256. onReply: _cache[1] || (_cache[1] = ($event) => $data.isSticky = !$data.isSticky)
  6257. }, {
  6258. default: vue.withCtx(() => [
  6259. vue.createVNode(_component_Point, {
  6260. onAddThank: $options.addThank,
  6261. onRecallThank: $options.recallThank,
  6262. item: {
  6263. isThanked: $options.post.isThanked,
  6264. thankCount: $options.post.thankCount,
  6265. username: $options.post.username
  6266. },
  6267. "api-url": "topic/" + $options.post.id
  6268. }, null, 8, ["onAddThank", "onRecallThank", "item", "api-url"])
  6269. ]),
  6270. _: 1
  6271. })
  6272. ]),
  6273. $options.post.topReplyList.length && $options.config.showTopReply ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_28, [
  6274. vue.createElementVNode("div", {
  6275. class: "my-cell flex",
  6276. onClick: _cache[2] || (_cache[2] = vue.withModifiers((...args) => $options.collapseTopReplyList && $options.collapseTopReplyList(...args), ["stop"]))
  6277. }, [
  6278. _hoisted_29,
  6279. vue.createElementVNode("div", _hoisted_30, [
  6280. vue.createVNode(_component_Tooltip, { title: "收起高赞回复" }, {
  6281. default: vue.withCtx(() => [
  6282. vue.createElementVNode("div", _hoisted_31, [
  6283. vue.createVNode(_component_Icon, { icon: "gravity-ui:chevrons-collapse-vertical" })
  6284. ])
  6285. ]),
  6286. _: 1
  6287. })
  6288. ])
  6289. ]),
  6290. vue.createElementVNode("div", _hoisted_32, [
  6291. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.post.topReplyList, (item, index) => {
  6292. return vue.openBlock(), vue.createBlock(_component_Comment, {
  6293. key: item.floor,
  6294. type: "top",
  6295. modelValue: $options.post.topReplyList[index],
  6296. "onUpdate:modelValue": ($event) => $options.post.topReplyList[index] = $event
  6297. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  6298. }), 128))
  6299. ], 512)
  6300. ])) : vue.createCommentVNode("", true),
  6301. vue.createElementVNode("div", _hoisted_33, [
  6302. $options.post.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_34, [
  6303. vue.createElementVNode("div", null, [
  6304. vue.createTextVNode(vue.toDisplayString($options.post.replyCount) + " 条回复 ", 1),
  6305. $options.post.lastReplyDate ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_35, [
  6306. vue.createTextVNode("  "),
  6307. _hoisted_36,
  6308. vue.createTextVNode("  " + vue.toDisplayString($options.post.lastReplyDate), 1)
  6309. ])) : vue.createCommentVNode("", true)
  6310. ]),
  6311. $options.config.showToolbar ? (vue.openBlock(), vue.createBlock(_component_BaseSelect, {
  6312. key: 0,
  6313. "display-type": $props.displayType,
  6314. "onUpdate:displayType": _cache[3] || (_cache[3] = (e2) => _ctx.$emit("update:displayType", e2))
  6315. }, null, 8, ["display-type"])) : (vue.openBlock(), vue.createElementBlock("div", {
  6316. key: 1,
  6317. class: "fr",
  6318. innerHTML: $options.post.fr
  6319. }, null, 8, _hoisted_37))
  6320. ])) : vue.createCommentVNode("", true),
  6321. $options.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  6322. $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_38, [
  6323. vue.createVNode(_component_BaseLoading, { size: "large" })
  6324. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_39, [
  6325. $props.modelValue ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 0 }, vue.renderList($options.replyList, (item, index) => {
  6326. return vue.openBlock(), vue.createBlock(_component_Comment, {
  6327. key: item.floor,
  6328. modelValue: $options.replyList[index],
  6329. "onUpdate:modelValue": ($event) => $options.replyList[index] = $event
  6330. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  6331. }), 128)) : vue.createCommentVNode("", true)
  6332. ]))
  6333. ], 64)) : vue.createCommentVNode("", true)
  6334. ]),
  6335. !($options.replyList.length || $props.loading) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_40, "目前尚无回复")) : vue.createCommentVNode("", true),
  6336. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
  6337. key: 2,
  6338. class: vue.normalizeClass(["my-box", { "sticky": $data.isSticky }]),
  6339. ref: "replyBox"
  6340. }, [
  6341. vue.createElementVNode("div", _hoisted_41, [
  6342. _hoisted_42,
  6343. vue.createElementVNode("div", _hoisted_43, [
  6344. $data.isSticky ? (vue.openBlock(), vue.createElementBlock("a", {
  6345. key: 0,
  6346. style: { "margin-right": "2rem" },
  6347. onClick: _cache[4] || (_cache[4] = vue.withModifiers(($event) => $data.isSticky = false, ["stop"]))
  6348. }, "取消回复框停靠")) : vue.createCommentVNode("", true),
  6349. vue.createElementVNode("a", {
  6350. onClick: _cache[5] || (_cache[5] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
  6351. }, "回到顶部")
  6352. ])
  6353. ]),
  6354. vue.createElementVNode("div", _hoisted_44, [
  6355. vue.createVNode(_component_PostEditor, {
  6356. onClose: $options.goBottom,
  6357. ref: "post-editor",
  6358. useType: "reply-post",
  6359. onClick: _cache[6] || (_cache[6] = vue.withModifiers(($event) => $data.isSticky = true, ["stop"]))
  6360. }, null, 8, ["onClose"])
  6361. ])
  6362. ], 2)) : vue.createCommentVNode("", true)
  6363. ], 4),
  6364. $data.showRelationReply ? (vue.openBlock(), vue.createElementBlock("div", {
  6365. key: 0,
  6366. class: "relationReply",
  6367. onClick: _cache[10] || (_cache[10] = vue.withModifiers(($event) => $options.close("space"), ["stop"]))
  6368. }, [
  6369. vue.createElementVNode("div", {
  6370. class: "my-cell flex",
  6371. onClick: _cache[8] || (_cache[8] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  6372. }, [
  6373. _hoisted_45,
  6374. vue.createElementVNode("div", _hoisted_46, [
  6375. vue.createVNode(_component_Icon, {
  6376. icon: "ic:round-close",
  6377. onClick: _cache[7] || (_cache[7] = vue.withModifiers(($event) => $data.showRelationReply = false, ["stop"]))
  6378. })
  6379. ])
  6380. ]),
  6381. vue.createElementVNode("div", {
  6382. class: "comments",
  6383. onClick: _cache[9] || (_cache[9] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  6384. }, [
  6385. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.relationReply, (item, index) => {
  6386. return vue.openBlock(), vue.createBlock(_component_SingleComment, {
  6387. "is-right": item.username === $data.targetUser.right,
  6388. key: item.floor,
  6389. comment: item
  6390. }, null, 8, ["is-right", "comment"]);
  6391. }), 128))
  6392. ])
  6393. ])) : vue.createCommentVNode("", true),
  6394. $data.showCallList && $options.filterCallList.length ? (vue.openBlock(), vue.createElementBlock("div", {
  6395. key: 1,
  6396. class: "call-list",
  6397. style: vue.normalizeStyle($data.callStyle)
  6398. }, [
  6399. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.filterCallList, (item, index) => {
  6400. return vue.openBlock(), vue.createElementBlock("div", {
  6401. class: vue.normalizeClass(["call-item", { select: index === $data.selectCallIndex }]),
  6402. onClick: vue.withModifiers(($event) => $options.setCall(item), ["stop"])
  6403. }, [
  6404. vue.createElementVNode("a", null, vue.toDisplayString(item), 1)
  6405. ], 10, _hoisted_47);
  6406. }), 256))
  6407. ], 4)) : vue.createCommentVNode("", true),
  6408. vue.createElementVNode("div", {
  6409. class: "close-btn",
  6410. onClick: _cache[11] || (_cache[11] = vue.withModifiers(($event) => $options.close("btn"), ["stop"]))
  6411. }, [
  6412. vue.createVNode(_component_Icon, { icon: "icon-park-outline:close" })
  6413. ]),
  6414. vue.createElementVNode("div", {
  6415. class: "open-new-tab",
  6416. onClick: _cache[12] || (_cache[12] = vue.withModifiers(($event) => $options.functions.openNewTab("https://www.v2ex.com/t/" + $options.post.id, $options.config.newTabOpenActive), ["stop"]))
  6417. }, [
  6418. vue.createVNode(_component_Icon, { icon: "majesticons:open" })
  6419. ]),
  6420. vue.createElementVNode("div", {
  6421. class: "refresh gray",
  6422. onClick: _cache[13] || (_cache[13] = vue.withModifiers(($event) => _ctx.$emit("refresh"), ["stop"]))
  6423. }, [
  6424. $props.refreshLoading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, { key: 0 })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  6425. key: 1,
  6426. icon: "material-symbols:refresh"
  6427. }))
  6428. ]),
  6429. vue.createElementVNode("div", {
  6430. class: "scroll-to gray",
  6431. onClick: _cache[17] || (_cache[17] = vue.withModifiers(($event) => $options.jump($data.currentFloor), ["stop"]))
  6432. }, [
  6433. vue.createVNode(_component_Icon, { icon: "lucide:move-down" }),
  6434. vue.withDirectives(vue.createElementVNode("input", {
  6435. type: "text",
  6436. "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.currentFloor = $event),
  6437. onClick: _cache[15] || (_cache[15] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"])),
  6438. onKeydown: _cache[16] || (_cache[16] = vue.withKeys(($event) => $options.jump($data.currentFloor), ["enter"]))
  6439. }, null, 544), [
  6440. [vue.vModelText, $data.currentFloor]
  6441. ])
  6442. ]),
  6443. vue.createElementVNode("div", {
  6444. class: "v2next-scroll-top gray",
  6445. onClick: _cache[18] || (_cache[18] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
  6446. }, [
  6447. vue.createVNode(_component_Icon, { icon: "lucide:move-up" })
  6448. ])
  6449. ], 2),
  6450. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  6451. vue.createElementVNode("div", {
  6452. class: "preview-modal",
  6453. onWheel: _cache[21] || (_cache[21] = (...args) => $options.wheel && $options.wheel(...args))
  6454. }, [
  6455. vue.createElementVNode("div", {
  6456. class: "mask",
  6457. onClick: _cache[20] || (_cache[20] = (...args) => $options.closePreviewModal && $options.closePreviewModal(...args))
  6458. }),
  6459. vue.createVNode(_component_Icon, {
  6460. class: "close",
  6461. icon: "fontisto:close-a",
  6462. onClick: $options.closePreviewModal
  6463. }, null, 8, ["onClick"])
  6464. ], 32)
  6465. ]))
  6466. ], 34)), [
  6467. [vue.vShow, $props.modelValue]
  6468. ]);
  6469. }
  6470. const PostDetail = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$2], ["__scopeId", "data-v-d39217d8"]]);
  6471. const _hoisted_1$5 = { key: 1 };
  6472. const _sfc_main$5 = {
  6473. __name: "Base64Tooltip",
  6474. setup(__props) {
  6475. const tooltip = vue.ref(null);
  6476. const show = vue.ref(false);
  6477. const originalText = vue.ref("");
  6478. const decodeText = vue.ref("");
  6479. const styleObject = vue.reactive({
  6480. left: "-100vw",
  6481. top: "-100vh"
  6482. });
  6483. vue.onMounted(() => {
  6484. eventBus.on(CMD.SHOW_TOOLTIP, ({ text, e: e2 }) => {
  6485. setTimeout(() => show.value = true);
  6486. originalText.value = text;
  6487. decodeText.value = "";
  6488. styleObject.left = e2.clientX + "px";
  6489. styleObject.top = e2.clientY + 20 + "px";
  6490. });
  6491. window.addEventListener("click", (e2) => {
  6492. if (!tooltip.value)
  6493. return;
  6494. if (!tooltip.value.contains(e2.target) && show.value) {
  6495. show.value = false;
  6496. }
  6497. }, { capture: true });
  6498. const fn = () => show.value && (show.value = false);
  6499. $(".post-detail", document).on("scroll", fn);
  6500. });
  6501. function copy() {
  6502. if (navigator.clipboard) {
  6503. navigator.clipboard.writeText(decodeText.value);
  6504. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "复制成功" });
  6505. } else {
  6506. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "复制失败!浏览器不支持!" });
  6507. }
  6508. }
  6509. function base64ToArrayBuffer(base64) {
  6510. let binary_string = window.atob(base64);
  6511. let len = binary_string.length;
  6512. let bytes = new Uint8Array(len);
  6513. for (let i = 0; i < len; i++) {
  6514. bytes[i] = binary_string.charCodeAt(i);
  6515. }
  6516. return bytes.buffer;
  6517. }
  6518. function decode() {
  6519. try {
  6520. new Blob([base64ToArrayBuffer(originalText.value)]).text().then((r2) => {
  6521. decodeText.value = r2;
  6522. });
  6523. } catch (e2) {
  6524. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "Base64解码失败!不是标准数据!" });
  6525. }
  6526. }
  6527. return (_ctx, _cache) => {
  6528. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  6529. class: "base64_tooltip",
  6530. style: vue.normalizeStyle(styleObject),
  6531. onClick: decode,
  6532. ref_key: "tooltip",
  6533. ref: tooltip
  6534. }, [
  6535. !decodeText.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  6536. vue.createTextVNode(" Base64解码:" + vue.toDisplayString(originalText.value) + " ", 1),
  6537. vue.createVNode(vue.unref(Icon), { icon: "system-uicons:translate" })
  6538. ], 64)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$5, [
  6539. vue.createElementVNode("span", null, vue.toDisplayString(decodeText.value), 1),
  6540. vue.createVNode(BaseButton, {
  6541. class: "btn",
  6542. size: "small",
  6543. onClick: copy
  6544. }, {
  6545. default: vue.withCtx(() => [
  6546. vue.createTextVNode("点击复制")
  6547. ]),
  6548. _: 1
  6549. })
  6550. ]))
  6551. ], 4)), [
  6552. [vue.vShow, show.value]
  6553. ]);
  6554. };
  6555. }
  6556. };
  6557. const Base64Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-06429e70"]]);
  6558. const _sfc_main$4 = {
  6559. name: "Msg",
  6560. components: { Icon },
  6561. props: {
  6562. type: "",
  6563. text: ""
  6564. },
  6565. created() {
  6566. setTimeout(() => {
  6567. this.$emit("close");
  6568. }, 3e3);
  6569. }
  6570. };
  6571. const _hoisted_1$4 = { class: "right" };
  6572. function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
  6573. const _component_Icon = vue.resolveComponent("Icon");
  6574. return vue.openBlock(), vue.createElementBlock("div", {
  6575. class: vue.normalizeClass(["msg", $props.type])
  6576. }, [
  6577. vue.createElementVNode("div", {
  6578. class: "left",
  6579. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
  6580. }, [
  6581. vue.createVNode(_component_Icon, { icon: "ic:round-close" })
  6582. ]),
  6583. vue.createElementVNode("div", _hoisted_1$4, vue.toDisplayString($props.text), 1)
  6584. ], 2);
  6585. }
  6586. const Msg = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$1], ["__scopeId", "data-v-8bf692ea"]]);
  6587. const _withScopeId$2 = (n2) => (vue.pushScopeId("data-v-0f1f99f7"), n2 = n2(), vue.popScopeId(), n2);
  6588. const _hoisted_1$3 = {
  6589. key: 0,
  6590. class: "tag-modal modal"
  6591. };
  6592. const _hoisted_2$2 = { class: "wrapper" };
  6593. const _hoisted_3$2 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 添加标签 ", -1));
  6594. const _hoisted_4$2 = { class: "option" };
  6595. const _hoisted_5$2 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户:", -1));
  6596. const _hoisted_6$2 = { class: "btns" };
  6597. const _sfc_main$3 = {
  6598. __name: "TagModal",
  6599. props: ["tags"],
  6600. emits: ["update:tags"],
  6601. setup(__props, { emit: __emit }) {
  6602. const tagModal = vue.reactive({
  6603. show: false,
  6604. currentUsername: "",
  6605. tag: ""
  6606. });
  6607. const props = __props;
  6608. const emit = __emit;
  6609. const inputRef = vue.ref();
  6610. vue.onMounted(() => {
  6611. eventBus.on(CMD.ADD_TAG, (username) => {
  6612. tagModal.currentUsername = username;
  6613. tagModal.show = true;
  6614. vue.nextTick(() => {
  6615. inputRef.value.focus();
  6616. });
  6617. });
  6618. });
  6619. async function addTag() {
  6620. if (!tagModal.tag) {
  6621. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请输入标签" });
  6622. return;
  6623. }
  6624. let oldTag = functions.clone(props.tags);
  6625. let tempTag = functions.clone(props.tags);
  6626. let userTags = tempTag[tagModal.currentUsername] ?? [];
  6627. let rIndex = userTags.findIndex((v) => v === tagModal.tag);
  6628. if (rIndex > -1) {
  6629. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "标签已存在!" });
  6630. return;
  6631. } else {
  6632. userTags.push(tagModal.tag);
  6633. }
  6634. tempTag[tagModal.currentUsername] = userTags;
  6635. emit("update:tags", tempTag);
  6636. tagModal.tag = "";
  6637. tagModal.show = false;
  6638. let res = await window.parse.saveTags(tempTag);
  6639. if (!res) {
  6640. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签添加失败!" });
  6641. emit("update:tags", oldTag);
  6642. }
  6643. }
  6644. return (_ctx, _cache) => {
  6645. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  6646. default: vue.withCtx(() => [
  6647. tagModal.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
  6648. vue.createElementVNode("div", {
  6649. class: "mask",
  6650. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => tagModal.show = false, ["stop"]))
  6651. }),
  6652. vue.createElementVNode("div", _hoisted_2$2, [
  6653. _hoisted_3$2,
  6654. vue.createElementVNode("div", _hoisted_4$2, [
  6655. _hoisted_5$2,
  6656. vue.createElementVNode("div", null, [
  6657. vue.createElementVNode("b", null, vue.toDisplayString(tagModal.currentUsername), 1)
  6658. ])
  6659. ]),
  6660. vue.withDirectives(vue.createElementVNode("input", {
  6661. type: "text",
  6662. ref_key: "inputRef",
  6663. ref: inputRef,
  6664. style: { "width": "100%" },
  6665. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tagModal.tag = $event),
  6666. onKeydown: vue.withKeys(addTag, ["enter"])
  6667. }, null, 544), [
  6668. [vue.vModelText, tagModal.tag]
  6669. ]),
  6670. vue.createElementVNode("div", _hoisted_6$2, [
  6671. vue.createVNode(BaseButton, {
  6672. type: "link",
  6673. onClick: _cache[2] || (_cache[2] = vue.withModifiers(($event) => {
  6674. tagModal.show = false;
  6675. tagModal.tag = "";
  6676. }, ["stop"]))
  6677. }, {
  6678. default: vue.withCtx(() => [
  6679. vue.createTextVNode("取消")
  6680. ]),
  6681. _: 1
  6682. }),
  6683. vue.createVNode(BaseButton, {
  6684. onClick: vue.withModifiers(addTag, ["stop"])
  6685. }, {
  6686. default: vue.withCtx(() => [
  6687. vue.createTextVNode("确定")
  6688. ]),
  6689. _: 1
  6690. })
  6691. ])
  6692. ])
  6693. ])) : vue.createCommentVNode("", true)
  6694. ]),
  6695. _: 1
  6696. });
  6697. };
  6698. }
  6699. };
  6700. const TagModal = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-0f1f99f7"]]);
  6701. const _hoisted_1$2 = { class: "msgs" };
  6702. const _sfc_main$2 = {
  6703. __name: "MsgModal",
  6704. setup(__props) {
  6705. const msgList = vue.reactive([
  6706. // {type: 'success', text: '123', id: Date.now()}
  6707. ]);
  6708. vue.onMounted(() => {
  6709. eventBus.on(CMD.SHOW_MSG, (val) => {
  6710. msgList.push({ ...val, id: Date.now() });
  6711. });
  6712. });
  6713. function removeMsg(id) {
  6714. let rIndex = msgList.findIndex((item) => item.id === id);
  6715. if (rIndex > -1) {
  6716. msgList.splice(rIndex, 1);
  6717. }
  6718. }
  6719. return (_ctx, _cache) => {
  6720. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
  6721. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(msgList, (v) => {
  6722. return vue.openBlock(), vue.createBlock(Msg, {
  6723. key: v.id,
  6724. type: v.type,
  6725. text: v.text,
  6726. onClose: ($event) => removeMsg(v.id)
  6727. }, null, 8, ["type", "text", "onClose"]);
  6728. }), 128))
  6729. ]);
  6730. };
  6731. }
  6732. };
  6733. const MsgModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b73f4332"]]);
  6734. let u = ".__cf_email__", f = "data-cfemail", d = document.createElement("div");
  6735. function e(e2) {
  6736. console.error(e2);
  6737. }
  6738. function r(e2, t) {
  6739. let r2 = e2.substr(t, 2);
  6740. return parseInt(r2, 16);
  6741. }
  6742. function n(href, index) {
  6743. let o = "", a = r(href, index);
  6744. for (let i = index + 2; i < href.length; i += 2) {
  6745. let l = r(href, i) ^ a;
  6746. o += String.fromCharCode(l);
  6747. }
  6748. try {
  6749. o = decodeURIComponent(escape(o));
  6750. } catch (u2) {
  6751. e(u2);
  6752. }
  6753. d.innerHTML = '<a href="' + o.replace(/"/g, "&quot;") + '"></a>';
  6754. return d.childNodes[0].getAttribute("href") || "";
  6755. }
  6756. function decodeEmail(body) {
  6757. try {
  6758. let as = body.find(u);
  6759. as.each(function() {
  6760. try {
  6761. let o = this, a = o.parentNode, i = o.getAttribute(f);
  6762. if (i) {
  6763. let l = n(i, 0), d2 = document.createTextNode(l);
  6764. a.replaceChild(d2, o);
  6765. }
  6766. } catch (h2) {
  6767. e(h2);
  6768. }
  6769. });
  6770. } catch (s) {
  6771. e(s);
  6772. }
  6773. }
  6774. const _withScopeId$1 = (n2) => (vue.pushScopeId("data-v-77aa374e"), n2 = n2(), vue.popScopeId(), n2);
  6775. const _hoisted_1$1 = {
  6776. key: 0,
  6777. class: "NotificationModal modal"
  6778. };
  6779. const _hoisted_2$1 = { class: "modal-root" };
  6780. const _hoisted_3$1 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 提醒系统 ", -1));
  6781. const _hoisted_4$1 = { class: "modal-body" };
  6782. const _hoisted_5$1 = { class: "filter" };
  6783. const _hoisted_6$1 = { class: "list-wrap" };
  6784. const _hoisted_7$1 = { class: "notify-wrap" };
  6785. const _hoisted_8$1 = ["innerHTML"];
  6786. const _hoisted_9$1 = {
  6787. key: 0,
  6788. class: "loading-wrap"
  6789. };
  6790. const _hoisted_10$1 = { class: "footer" };
  6791. const _hoisted_11$1 = ["innerHTML"];
  6792. const _hoisted_12$1 = { class: "total" };
  6793. const _hoisted_13$1 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("span", null, "总共收到提醒", -1));
  6794. const _sfc_main$1 = {
  6795. __name: "NotificationModal",
  6796. props: ["modelValue", "list", "total", "pages", "loading"],
  6797. emits: ["update:modelValue"],
  6798. setup(__props, { emit: __emit }) {
  6799. const props = __props;
  6800. const emit = __emit;
  6801. const index = vue.ref("all");
  6802. vue.onMounted(() => {
  6803. });
  6804. vue.watch([index, () => props.list], () => {
  6805. $(".notify-wrap").scrollTop(0);
  6806. });
  6807. vue.watch(() => props.modelValue, (n2) => {
  6808. if (n2) {
  6809. document.body.style.overflow = "hidden";
  6810. } else {
  6811. document.body.style.overflow = "unset";
  6812. $(".notify-wrap").scrollTop(0);
  6813. }
  6814. });
  6815. function close() {
  6816. emit("update:modelValue", false);
  6817. }
  6818. return (_ctx, _cache) => {
  6819. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  6820. default: vue.withCtx(() => [
  6821. __props.modelValue ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
  6822. vue.createElementVNode("div", {
  6823. class: "mask",
  6824. onClick: vue.withModifiers(close, ["stop"])
  6825. }),
  6826. vue.createElementVNode("div", _hoisted_2$1, [
  6827. vue.createElementVNode("div", { class: "modal-header" }, [
  6828. _hoisted_3$1,
  6829. vue.createElementVNode("i", {
  6830. class: "fa fa-times",
  6831. onClick: close
  6832. })
  6833. ]),
  6834. vue.createElementVNode("div", _hoisted_4$1, [
  6835. vue.createElementVNode("div", _hoisted_5$1, [
  6836. vue.createElementVNode("div", {
  6837. class: vue.normalizeClass(index.value === "all" && "active"),
  6838. onClick: _cache[0] || (_cache[0] = ($event) => index.value = "all")
  6839. }, "全部", 2),
  6840. vue.createElementVNode("div", {
  6841. class: vue.normalizeClass(index.value === "reply" && "active"),
  6842. onClick: _cache[1] || (_cache[1] = ($event) => index.value = "reply")
  6843. }, "回复", 2),
  6844. vue.createElementVNode("div", {
  6845. class: vue.normalizeClass(index.value === "star" && "active"),
  6846. onClick: _cache[2] || (_cache[2] = ($event) => index.value = "star")
  6847. }, "感谢", 2),
  6848. vue.createElementVNode("div", {
  6849. class: vue.normalizeClass(index.value === "collect" && "active"),
  6850. onClick: _cache[3] || (_cache[3] = ($event) => index.value = "collect")
  6851. }, "收藏", 2)
  6852. ]),
  6853. vue.createElementVNode("div", _hoisted_6$1, [
  6854. vue.createElementVNode("div", _hoisted_7$1, [
  6855. vue.createElementVNode("div", {
  6856. id: "notifications",
  6857. class: vue.normalizeClass(index.value),
  6858. innerHTML: __props.list
  6859. }, null, 10, _hoisted_8$1)
  6860. ]),
  6861. __props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$1, [
  6862. vue.createVNode(BaseLoading)
  6863. ])) : vue.createCommentVNode("", true)
  6864. ]),
  6865. vue.createElementVNode("div", _hoisted_10$1, [
  6866. vue.createElementVNode("div", {
  6867. innerHTML: __props.pages,
  6868. class: "pages"
  6869. }, null, 8, _hoisted_11$1),
  6870. vue.createElementVNode("div", _hoisted_12$1, [
  6871. _hoisted_13$1,
  6872. vue.createTextVNode(vue.toDisplayString(__props.total), 1)
  6873. ])
  6874. ])
  6875. ])
  6876. ])
  6877. ])) : vue.createCommentVNode("", true)
  6878. ]),
  6879. _: 1
  6880. });
  6881. };
  6882. }
  6883. };
  6884. const NotificationModal = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-77aa374e"]]);
  6885. const _sfc_main = {
  6886. components: {
  6887. Icon,
  6888. BaseButton,
  6889. NotificationModal,
  6890. BaseLoading,
  6891. BaseSwitch,
  6892. MsgModal,
  6893. TagModal,
  6894. Tooltip,
  6895. Setting,
  6896. PostDetail,
  6897. Base64Tooltip,
  6898. Msg
  6899. },
  6900. provide() {
  6901. return {
  6902. isLogin: vue.computed(() => this.isLogin),
  6903. isNight: vue.computed(() => this.isNight),
  6904. pageType: vue.computed(() => this.pageType),
  6905. tags: vue.computed(() => this.tags),
  6906. show: vue.computed(() => this.show),
  6907. post: vue.computed(() => this.current),
  6908. config: vue.computed(() => this.config),
  6909. allReplyUsers: vue.computed(() => {
  6910. var _a, _b, _c;
  6911. if ((_a = this.current) == null ? void 0 : _a.replyList) {
  6912. return Array.from(new Set(((_c = (_b = this.current) == null ? void 0 : _b.replyList) == null ? void 0 : _c.map((v) => v.username)) ?? []));
  6913. }
  6914. return [];
  6915. }),
  6916. showConfig: this.showConfig
  6917. };
  6918. },
  6919. data() {
  6920. return {
  6921. loading: window.pageType === PageType.Post,
  6922. refreshLoading: false,
  6923. loadMore: false,
  6924. isLogin: !!window.user.username,
  6925. pageType: window.pageType,
  6926. isNight: window.isNight,
  6927. stopMe: window.stopMe,
  6928. //停止使用脚本
  6929. show: false,
  6930. current: getDefaultPost(),
  6931. list: [],
  6932. config: functions.clone(window.config),
  6933. tags: window.user.tags,
  6934. configModal: {
  6935. show: false
  6936. },
  6937. notificationModal: {
  6938. show: false,
  6939. loading: false,
  6940. list: "",
  6941. total: 0
  6942. },
  6943. previewModal: {
  6944. show: false,
  6945. src: ""
  6946. },
  6947. popConfirmModal: {
  6948. show: false,
  6949. title: "",
  6950. id: ""
  6951. },
  6952. timer: -1,
  6953. timer2: -1,
  6954. pageInfo: {
  6955. title: "",
  6956. number: 0
  6957. },
  6958. calendar: {
  6959. show: false,
  6960. year: "",
  6961. month: "",
  6962. dayCount: 0,
  6963. firstDayWeek: 0,
  6964. select: ""
  6965. }
  6966. };
  6967. },
  6968. computed: {
  6969. targetUserTags() {
  6970. return this.tags[window.targetUserName] ?? [];
  6971. },
  6972. isList() {
  6973. return [PageType.Home, PageType.Node].includes(this.pageType);
  6974. },
  6975. isPost() {
  6976. return this.pageType === PageType.Post;
  6977. },
  6978. isMember() {
  6979. return this.pageType === PageType.Member;
  6980. }
  6981. },
  6982. watch: {
  6983. config: {
  6984. handler(newVal, oldVal) {
  6985. console.log("config", functions.clone(newVal).notice, functions.clone(oldVal).notice);
  6986. let configStr = localStorage.getItem("v2ex-config");
  6987. if (configStr) {
  6988. let configObj = JSON.parse(configStr);
  6989. configObj[window.user.username || "default"] = newVal;
  6990. localStorage.setItem("v2ex-config", JSON.stringify(configObj));
  6991. }
  6992. window.config = newVal;
  6993. window.parse.editNoteItem(window.user.configPrefix + JSON.stringify(window.config), window.user.configNoteId);
  6994. },
  6995. deep: true
  6996. },
  6997. tags(newVal) {
  6998. window.user.tags = newVal;
  6999. },
  7000. "config.viewType"(newVal) {
  7001. if (!newVal)
  7002. return;
  7003. if (newVal === "card") {
  7004. $(".post-item").each(function() {
  7005. $(this).addClass("preview");
  7006. });
  7007. } else {
  7008. $(".post-item").each(function() {
  7009. $(this).removeClass("preview");
  7010. });
  7011. }
  7012. },
  7013. "pageInfo.number"(newVal) {
  7014. clearInterval(this.timer2);
  7015. if (newVal) {
  7016. document.title = `(${this.pageInfo.number}) ` + this.pageInfo.title;
  7017. if (this.config.notice.whenNewNoticeGlimmer) {
  7018. let c = 0;
  7019. this.timer2 = setInterval(() => {
  7020. c++;
  7021. document.title = this.pageInfo.title;
  7022. if (c % 2 === 0) {
  7023. document.title = `(${this.pageInfo.number}) ` + this.pageInfo.title;
  7024. }
  7025. }, 1e3);
  7026. }
  7027. } else {
  7028. document.title = this.pageInfo.title;
  7029. }
  7030. },
  7031. show(newVal) {
  7032. if (this.pageType === PageType.Post)
  7033. return;
  7034. if (newVal) {
  7035. document.body.style.overflow = "hidden";
  7036. if (!window.history.state) {
  7037. window.history.pushState({}, 0, this.current.href);
  7038. }
  7039. vue.nextTick(() => {
  7040. this.pageInfo.title = document.title = this.current.title ?? "V2EX";
  7041. });
  7042. } else {
  7043. document.body.style.overflow = "unset";
  7044. this.pageInfo.title = document.title = "V2EX";
  7045. if (window.history.state) {
  7046. window.history.back();
  7047. }
  7048. }
  7049. }
  7050. },
  7051. created() {
  7052. let that = this;
  7053. this.initEvent();
  7054. window.cb = this.winCb;
  7055. if (!window.canParseV2exPage)
  7056. return;
  7057. $(document).on("click", "a", this.clickA);
  7058. $(document).on("click", ".post-item", function(e2) {
  7059. if (e2.currentTarget.getAttribute("script"))
  7060. return;
  7061. if (that.stopMe)
  7062. return true;
  7063. if (this.classList.contains("preview")) {
  7064. if (e2.target.tagName !== "A" && e2.target.tagName !== "IMG" && !e2.target.classList.contains("toggle")) {
  7065. let id = this.dataset["id"];
  7066. let href = this.dataset["href"];
  7067. if (id) {
  7068. that.clickPost(e2, id, href);
  7069. } else {
  7070. if (href)
  7071. location.href = href;
  7072. }
  7073. }
  7074. }
  7075. });
  7076. $(document).on("click", ".toggle", (e2) => {
  7077. if (this.stopMe)
  7078. return true;
  7079. let id = e2.target.dataset["id"];
  7080. let itemDom = document.querySelector(`.id_${id}`);
  7081. if (itemDom.classList.contains("preview")) {
  7082. e2.target.innerText = "预览";
  7083. itemDom.classList.remove("preview");
  7084. } else {
  7085. if (this.config.viewType !== "card") {
  7086. let index = this.list.findIndex((v) => v.id == id);
  7087. if (index > -1) {
  7088. e2.target.innerText = "收起";
  7089. itemDom.classList.add("preview");
  7090. } else {
  7091. e2.target.innerText = "加载中";
  7092. functions.getPostDetailByApi(id).then((res) => {
  7093. if (res.content_rendered) {
  7094. res.href = itemDom.dataset["href"];
  7095. this.list.push(getDefaultPost(res));
  7096. itemDom.classList.add("preview");
  7097. e2.target.innerText = "收起";
  7098. functions.appendPostContent(res, itemDom);
  7099. } else {
  7100. e2.target.innerText = "预览";
  7101. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "主题暂无正文!" });
  7102. }
  7103. });
  7104. }
  7105. } else {
  7106. e2.target.innerText = "收起";
  7107. itemDom.classList.add("preview");
  7108. }
  7109. }
  7110. });
  7111. window.onpopstate = (event) => {
  7112. if (event.state) {
  7113. if (!this.show)
  7114. this.show = true;
  7115. } else {
  7116. if (this.show)
  7117. this.show = false;
  7118. }
  7119. };
  7120. if (this.config.notice.takeOverNoticePage) {
  7121. window.deleteNotification = (nId, token) => {
  7122. let item = $("#n_" + nId);
  7123. item.slideUp("fast");
  7124. $.post({
  7125. url: "/delete/notification/" + nId + "?once=" + token,
  7126. success() {
  7127. $.get({
  7128. url: "/notifications/below/" + window.notificationBottom,
  7129. success(data, status, request) {
  7130. item.remove();
  7131. $("#notifications").append(that.checkReplyItemType(data));
  7132. window.notificationBottom = request.getResponseHeader("X-V2EX-New-Notification-Bottom");
  7133. },
  7134. error() {
  7135. item.slideDown("fast");
  7136. }
  7137. });
  7138. },
  7139. error() {
  7140. item.slideDown("fast");
  7141. }
  7142. });
  7143. };
  7144. }
  7145. },
  7146. beforeUnmount() {
  7147. clearInterval(this.timer);
  7148. eventBus.clear();
  7149. $(document).off("click", "a", this.clickA);
  7150. },
  7151. methods: {
  7152. getMonthDayInfo(num) {
  7153. let now = dayjs();
  7154. now = now.year(this.calendar.year);
  7155. now = now.month(this.calendar.month);
  7156. if (num > 0) {
  7157. now = now.add(1, "month");
  7158. } else {
  7159. now = now.subtract(1, "month");
  7160. }
  7161. this.calendar.year = now.year();
  7162. this.calendar.month = now.month();
  7163. this.calendar.dayCount = now.daysInMonth();
  7164. this.calendar.firstDayWeek = now.startOf("month").day();
  7165. },
  7166. checkReplyItemType(val) {
  7167. let d2 = $(val);
  7168. let str = d2.html();
  7169. if (str.includes("提到了你") || str.includes("回复了你")) {
  7170. d2.addClass("reply");
  7171. }
  7172. if (str.includes("感谢了你")) {
  7173. d2.addClass("star");
  7174. }
  7175. if (str.includes("收藏了你")) {
  7176. d2.addClass("collect");
  7177. }
  7178. return d2;
  7179. },
  7180. async getUnreadMessagesCount() {
  7181. var _a, _b;
  7182. const res = await fetch(`${location.origin}/mission`);
  7183. const htmlText = await res.text();
  7184. const $page = $(htmlText);
  7185. const text = $page.find('#Rightbar a[href^="/notifications"]').text();
  7186. if (text.includes("未读提醒")) {
  7187. const countStr = (_a = text.match(/\d+/)) == null ? void 0 : _a.at(0);
  7188. if (countStr) {
  7189. return Number((_b = text.match(/\d+/)) == null ? void 0 : _b.at(0));
  7190. }
  7191. } else {
  7192. return 0;
  7193. }
  7194. throw new Error("无法获取未读消息数量");
  7195. },
  7196. clickA(e2) {
  7197. let that = this;
  7198. if (e2.currentTarget.getAttribute("script"))
  7199. return;
  7200. if (that.stopMe)
  7201. return true;
  7202. let { pageType } = functions.checkPageType(e2.currentTarget);
  7203. let { href, id, title } = functions.parseA(e2.currentTarget);
  7204. switch (pageType) {
  7205. case PageType.Post:
  7206. if (id) {
  7207. that.clickPost(e2, id, href, title);
  7208. }
  7209. break;
  7210. case PageType.Node:
  7211. case PageType.Home:
  7212. case PageType.Changes:
  7213. return;
  7214. case PageType.Hot:
  7215. let date = e2.currentTarget.search.replace("?", "");
  7216. if (date === "setting") {
  7217. if (this.calendar.show) {
  7218. $("#Rightbar > .sep20:first").css("height", "var(--component-margin)");
  7219. } else {
  7220. $("#Rightbar > .sep20:first").css("height", "unset");
  7221. let now2 = dayjs();
  7222. this.calendar.year = now2.year();
  7223. this.calendar.month = now2.month();
  7224. this.calendar.dayCount = now2.daysInMonth();
  7225. this.calendar.firstDayWeek = now2.startOf("month").day();
  7226. this.calendar.select = `${this.calendar.year}-${this.calendar.month + 1}-${now2.date()}`;
  7227. }
  7228. this.calendar.show = !this.calendar.show;
  7229. functions.stopEvent(e2);
  7230. return;
  7231. }
  7232. let now = dayjs();
  7233. let day = "";
  7234. switch (Number(date)) {
  7235. case -1:
  7236. day = now.subtract(1, "day").format("YYYY-M-D");
  7237. break;
  7238. case -2:
  7239. day = now.subtract(2, "day").format("YYYY-M-D");
  7240. break;
  7241. case 3:
  7242. day = "3d";
  7243. break;
  7244. case 7:
  7245. day = "7d";
  7246. break;
  7247. case 30:
  7248. day = "30d";
  7249. break;
  7250. default:
  7251. day = date;
  7252. if (dayjs(day).isSame(now, "day")) {
  7253. functions.stopEvent(e2);
  7254. return location.reload();
  7255. }
  7256. }
  7257. if (day) {
  7258. fetch(DefaultVal.hotUrl + day + ".json").then(async (r2) => {
  7259. let r1 = await r2.json();
  7260. $(".cell.item.post-item").remove();
  7261. r1.reverse().map((v) => {
  7262. let s = `
  7263. <div class="cell item post-item id_${v.id}" style="" data-href="https://www.v2ex.com/t/${v.id}#reply${v.replyCount}">
  7264. <table cellpadding="0" cellspacing="0" border="0" width="100%">
  7265. <tbody>
  7266. <tr>
  7267. <td width="48" valign="top" align="center">
  7268. <a href="/member/${v.username}">
  7269. <img src="${v.avatar}" class="avatar"
  7270. border="0" align="default"
  7271. width="48"
  7272. style="width: 48px; max-height: 48px;"
  7273. alt="ice9191">
  7274. </a>
  7275. </td>
  7276. <td width="10"></td>
  7277. <td width="auto" valign="middle">
  7278. <span class="item_title">
  7279. <a href="https://www.v2ex.com/t/${v.id}#reply${v.replyCount}" class="topic-link" id="topic-link-${v.id}">${v.title}</a>
  7280. </span>
  7281. <div class="sep5"></div>
  7282. <span class="topic_info">
  7283. <div class="votes"></div>
  7284. <a class="node" href="/go/${v.nodeUrl}">${v.nodeTitle}</a> &nbsp;•&nbsp;
  7285. <strong><a href="/member/${v.username}">${v.username}</a></strong> &nbsp;•&nbsp;
  7286. <span title="${v.lastReplyDate}">${v.lastReplyDateAgo}</span> &nbsp;•&nbsp; 最后回复来自
  7287. <strong><a href="/member/${v.lastReplyUsername}">${v.lastReplyUsername}</a></strong>
  7288. </span>
  7289. </td>
  7290. <td width="70" align="right" valign="middle" style="position: relative;">
  7291. <a href="/t/${v.id}#reply${v.replyCount}" class="count_livid">${v.replyCount}</a>
  7292. <div data-id="${v.id}" class="toggle">预览</div>
  7293. </td>
  7294. </tr>
  7295. </tbody>
  7296. </table>
  7297. </div>
  7298. `;
  7299. $("#app").after($(s));
  7300. });
  7301. }).catch((e3) => {
  7302. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "暂无点击日期的最热数据!" });
  7303. });
  7304. }
  7305. functions.stopEvent(e2);
  7306. return;
  7307. default:
  7308. if (e2.currentTarget.href.includes("/settings/night/toggle"))
  7309. return;
  7310. if (e2.currentTarget.href === location.origin + "/#;")
  7311. return;
  7312. if (e2.currentTarget.href.includes("/notifications")) {
  7313. this.pageInfo.number = 0;
  7314. $("#money").parent().prev().replaceWith(`<a href="/notifications">0 未读提醒</a>`);
  7315. if (this.config.notice.takeOverNoticePage) {
  7316. this.notificationModal.loading = true;
  7317. this.notificationModal.show = true;
  7318. fetch(href).then(async (r2) => {
  7319. let htmlText = await r2.text();
  7320. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7321. let res = htmlText.match(/var notificationBottom = ([\d]+);/);
  7322. if (res && res[1]) {
  7323. window.notificationBottom = Number(res[1]);
  7324. console.log(" window.notificationBottom", window.notificationBottom);
  7325. }
  7326. let body = $(bodyText[0]);
  7327. let list = body.find("#notifications");
  7328. list.children().each(function() {
  7329. that.checkReplyItemType(this);
  7330. });
  7331. let h2 = list.html();
  7332. let d2 = body.find("#Main > .box > .header .fr .gray");
  7333. if (d2.length) {
  7334. this.notificationModal.total = d2.text();
  7335. }
  7336. this.notificationModal.list = h2;
  7337. let p = list.next();
  7338. let tds = p.find(".button");
  7339. tds.each(function() {
  7340. let href2 = this.getAttribute("onclick");
  7341. if (href2) {
  7342. this.innerHTML = `<a href=${href2.replace("location.href=", "")}>${this.innerHTML}</a>`;
  7343. this.setAttribute("onclick", "");
  7344. }
  7345. });
  7346. this.notificationModal.pages = p.html();
  7347. this.notificationModal.loading = false;
  7348. }).catch((e3) => {
  7349. this.notificationModal.loading = false;
  7350. });
  7351. functions.stopEvent(e2);
  7352. return;
  7353. }
  7354. }
  7355. if (that.config.newTabOpen) {
  7356. functions.stopEvent(e2);
  7357. functions.openNewTab(e2.currentTarget.href, that.config.newTabOpenActive);
  7358. }
  7359. return;
  7360. }
  7361. },
  7362. async clickPost(e2, id, href, title = "") {
  7363. if (id) {
  7364. if (this.config.clickPostItemOpenDetail) {
  7365. functions.stopEvent(e2);
  7366. let postItem = getDefaultPost();
  7367. let index = this.list.findIndex((v) => v.id == id);
  7368. if (index > -1) {
  7369. postItem = this.list[index];
  7370. }
  7371. if (!postItem.title)
  7372. postItem.title = title ?? "加载中";
  7373. postItem.id = id;
  7374. postItem.href = href;
  7375. this.getPostDetail(postItem);
  7376. return;
  7377. }
  7378. if (this.config.newTabOpen) {
  7379. functions.stopEvent(e2);
  7380. functions.openNewTab(`https://www.v2ex.com/t/${id}?p=1`, this.config.newTabOpenActive);
  7381. }
  7382. }
  7383. },
  7384. showPost() {
  7385. this.show = true;
  7386. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  7387. $(this).hide();
  7388. });
  7389. },
  7390. showConfig() {
  7391. this.configModal.show = true;
  7392. },
  7393. resetTitle() {
  7394. let r2 = document.title.match(/\s?\(\d+\)\s?/);
  7395. if (r2 && r2.length) {
  7396. this.pageInfo.title = document.title.replace(r2[0], "");
  7397. } else {
  7398. this.pageInfo.title = document.title;
  7399. }
  7400. },
  7401. async getNotice(body) {
  7402. if (!body) {
  7403. let res = await fetch("/t");
  7404. if (res.status === 200) {
  7405. let htmlText = await res.text();
  7406. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7407. body = $(bodyText[0]);
  7408. }
  7409. }
  7410. let notify = body.find('a[href="/notifications"]');
  7411. if (notify.length) {
  7412. this.resetTitle();
  7413. let text = notify.text();
  7414. if (text !== "0 未读提醒") {
  7415. this.pageInfo.number = text.replace(" 未读提醒", "");
  7416. console.log("text", text, this.config.notice.ddWebhook);
  7417. if (this.config.notice.text !== text) {
  7418. console.log("有新消息", text, this.config.notice.text);
  7419. $("#money").parent().prev().replaceWith(`<div><div class="orange-dot"></div><strong><a href="/notifications">${text}</a></strong></div>`);
  7420. this.config.notice.text = text;
  7421. if (this.config.notice.ddWebhook) {
  7422. let n2 = /* @__PURE__ */ new Date();
  7423. let s = n2.getSeconds();
  7424. s = s < 10 ? "0" + s : s;
  7425. let m = n2.getMinutes();
  7426. m = m < 10 ? "0" + m : m;
  7427. let h2 = n2.getHours();
  7428. h2 = h2 < 10 ? "0" + h2 : h2;
  7429. $.ajax("https://car-back.ttentau.top/index.php/v1/config/forward", {
  7430. method: "POST",
  7431. contentType: "application/json",
  7432. data: JSON.stringify({
  7433. url: this.config.notice.ddWebhook,
  7434. "text": notify.text() + `,时间:${n2.getFullYear()}/${n2.getMonth() + 1}/${n2.getDate()} ${h2}:${m}:${s}`
  7435. })
  7436. });
  7437. }
  7438. }
  7439. } else {
  7440. $("#money").parent().prev().replaceWith(`<a href="/notifications">${text}</a>`);
  7441. this.config.notice.text = "";
  7442. }
  7443. }
  7444. },
  7445. async winCb({ type, value }) {
  7446. console.log("回调的类型", type, value);
  7447. if (type === "openSetting") {
  7448. this.showConfig();
  7449. }
  7450. if (type === "syncData") {
  7451. this.stopMe = window.stopMe;
  7452. }
  7453. if (type === "getConfigSuccess") {
  7454. if (window.config.version < DefaultVal.currentVersion && window.isDeadline) {
  7455. $(".v2next-setting span").after(`<div class="new v2next-new">new</div>`);
  7456. }
  7457. if (window.isLogin && window.config.notice.loopCheckNotice) {
  7458. this.getNotice($(document.body));
  7459. this.timer = setInterval(this.getNotice, 1e3 * 60 * Number(window.config.notice.loopCheckNoticeInterval));
  7460. }
  7461. this.config = window.config;
  7462. this.tags = window.user.tags;
  7463. }
  7464. if (type === "syncList") {
  7465. this.list = Object.assign(this.list, window.postList);
  7466. }
  7467. if (type === "warningNotice") {
  7468. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: value });
  7469. }
  7470. if (this.stopMe)
  7471. return;
  7472. if (type === "restorePost") {
  7473. this.show = false;
  7474. this.loading = false;
  7475. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "脚本无法查看此页面!" });
  7476. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  7477. $(this).show();
  7478. });
  7479. }
  7480. if (type === "postContent") {
  7481. this.current = Object.assign(this.current, value);
  7482. this.current.inList = true;
  7483. if (this.config.autoOpenDetail) {
  7484. this.showPost();
  7485. }
  7486. }
  7487. if (type === "postReplies") {
  7488. this.loading = false;
  7489. this.current = Object.assign(this.current, value);
  7490. this.list.push(functions.clone(this.current));
  7491. }
  7492. },
  7493. regenerateReplyList() {
  7494. if (this.current.replyList.length) {
  7495. functions.createList(this.current, this.current.replyList);
  7496. } else {
  7497. this.current.replyCount = 0;
  7498. this.current.nestedReplies = [];
  7499. this.current.nestedRedundReplies = [];
  7500. }
  7501. if (this.list.length) {
  7502. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  7503. if (rIndex > -1) {
  7504. this.list[rIndex] = functions.clone(this.current);
  7505. }
  7506. }
  7507. },
  7508. initEvent() {
  7509. eventBus.on(CMD.CHANGE_COMMENT_THANK, (val) => {
  7510. const { id, type } = val;
  7511. let currentI = this.current.replyList.findIndex((i) => i.id === id);
  7512. if (currentI > -1) {
  7513. this.current.replyList[currentI].isThanked = type === "add";
  7514. if (type === "add") {
  7515. this.current.replyList[currentI].thankCount++;
  7516. } else {
  7517. this.current.replyList[currentI].thankCount--;
  7518. }
  7519. this.regenerateReplyList();
  7520. }
  7521. });
  7522. eventBus.on(CMD.CHANGE_POST_THANK, (val) => {
  7523. const { id, type } = val;
  7524. this.current.isThanked = type === "add";
  7525. if (type === "add") {
  7526. this.current.thankCount++;
  7527. } else {
  7528. this.current.thankCount--;
  7529. }
  7530. let currentI = this.list.findIndex((i) => i.id === id);
  7531. if (currentI > -1) {
  7532. this.list[currentI].isThanked = type === "add";
  7533. if (type === "add") {
  7534. this.list[currentI].thankCount++;
  7535. } else {
  7536. this.list[currentI].thankCount++;
  7537. }
  7538. }
  7539. });
  7540. eventBus.on(CMD.REMOVE, (val) => {
  7541. let removeIndex = this.current.replyList.findIndex((i) => i.floor === val);
  7542. if (removeIndex > -1) {
  7543. this.current.replyList.splice(removeIndex, 1);
  7544. }
  7545. this.regenerateReplyList();
  7546. });
  7547. eventBus.on(CMD.IGNORE, () => {
  7548. this.show = false;
  7549. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  7550. if (rIndex > -1) {
  7551. this.list.splice(rIndex, 1);
  7552. }
  7553. this.current = getDefaultPost();
  7554. });
  7555. eventBus.on(CMD.MERGE, (val) => {
  7556. this.current = Object.assign(this.current, val);
  7557. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  7558. if (rIndex > -1) {
  7559. this.list[rIndex] = functions.clone(this.current);
  7560. }
  7561. });
  7562. eventBus.on(CMD.ADD_REPLY, (item) => {
  7563. this.current.replyList.push(item);
  7564. this.regenerateReplyList();
  7565. });
  7566. eventBus.on(CMD.REFRESH_ONCE, async (once) => {
  7567. if (once) {
  7568. if (typeof once === "string") {
  7569. let res = once.match(/var once = "([\d]+)";/);
  7570. if (res && res[1]) {
  7571. this.current.once = Number(res[1]);
  7572. return;
  7573. }
  7574. }
  7575. if (typeof once === "number") {
  7576. this.current.once = once;
  7577. return;
  7578. }
  7579. }
  7580. window.fetchOnce().then((r2) => {
  7581. this.current.once = r2;
  7582. });
  7583. });
  7584. eventBus.on(CMD.REMOVE_TAG, async ({ username, tag }) => {
  7585. let oldTag = functions.clone(this.tags);
  7586. let tags = this.tags[username] ?? [];
  7587. let rIndex = tags.findIndex((v) => v === tag);
  7588. if (rIndex > -1) {
  7589. tags.splice(rIndex, 1);
  7590. }
  7591. this.tags[username] = tags;
  7592. let res = await window.parse.saveTags(this.tags);
  7593. if (!res) {
  7594. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签删除失败!" });
  7595. this.tags = oldTag;
  7596. }
  7597. });
  7598. eventBus.on(CMD.SHOW_CONFIRM_MODAL, (val) => {
  7599. const { rect, title, id } = val;
  7600. this.popConfirmModal.show = true;
  7601. this.popConfirmModal.title = title;
  7602. this.popConfirmModal.id = id;
  7603. vue.nextTick(() => {
  7604. this.$refs.tip.style.top = rect.top + "px";
  7605. this.$refs.tip.style.left = rect.left + rect.width / 2 - 50 + "px";
  7606. });
  7607. });
  7608. },
  7609. async getPostDetail(post) {
  7610. this.current = post;
  7611. this.show = true;
  7612. let url = location.origin + "/t/" + this.current.id;
  7613. this.current.url = url;
  7614. let alreadyHasReply = this.current.replyList.length;
  7615. if (alreadyHasReply) {
  7616. this.refreshLoading = true;
  7617. } else {
  7618. this.loading = true;
  7619. functions.getPostDetailByApi(this.current.id).then((d2) => {
  7620. d2.replyCount = d2.replies;
  7621. this.current = Object.assign(this.current, d2);
  7622. if (this.current.replyCount > window.config.maxReplyCountLimit) {
  7623. functions.openNewTab(`${location.origin}/t/${this.current.id}?p=1&script=1`, true);
  7624. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "由于回复数量较多,已为您单独打开此主题" });
  7625. this.loading = this.show = false;
  7626. return;
  7627. } else {
  7628. this.current.jsonContent = `
  7629. <div class="cell">
  7630. <div class="topic_content">
  7631. <div class="markdown_body">
  7632. ${(d2 == null ? void 0 : d2.content_rendered) ?? ""}
  7633. </div>
  7634. </div>
  7635. </div>`;
  7636. }
  7637. });
  7638. }
  7639. let apiRes = await window.fetch(url + "?p=1");
  7640. if (apiRes.status === 404) {
  7641. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "主题未找到" });
  7642. return this.refreshLoading = this.loading = false;
  7643. }
  7644. if (apiRes.status === 403) {
  7645. this.refreshLoading = this.show = this.loading = false;
  7646. functions.openNewTab(`${location.origin}/t/${post.id}?p=1&script=0`, true);
  7647. return;
  7648. }
  7649. if (apiRes.redirected) {
  7650. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有权限" });
  7651. return this.refreshLoading = this.loading = false;
  7652. }
  7653. let htmlText = await apiRes.text();
  7654. let hasPermission = htmlText.search("你要查看的页面需要先登录");
  7655. if (hasPermission > -1) {
  7656. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你要查看的页面需要先登录" });
  7657. return this.refreshLoading = this.loading = false;
  7658. }
  7659. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7660. let body = $(bodyText[0]);
  7661. decodeEmail(body);
  7662. await window.parse.getPostDetail(this.current, body, htmlText);
  7663. let index = this.list.findIndex((v) => v.id == this.current.id);
  7664. if (index > -1) {
  7665. this.list[index] = functions.clone(this.current);
  7666. } else {
  7667. this.list.push(functions.clone(this.current));
  7668. }
  7669. this.refreshLoading = this.loading = false;
  7670. await window.parse.parseOp(this.current);
  7671. console.log("当前主题", this.current);
  7672. },
  7673. addTargetUserTag() {
  7674. eventBus.emit(CMD.ADD_TAG, window.targetUserName);
  7675. },
  7676. removeTargetUserTag(tag) {
  7677. eventBus.emit(CMD.REMOVE_TAG, { username: window.targetUserName, tag });
  7678. },
  7679. popConfirmModalCancel() {
  7680. this.popConfirmModal.show = false;
  7681. },
  7682. popConfirmModalConfirm() {
  7683. this.popConfirmModalCancel();
  7684. eventBus.emit(CMD.SHOW_CONFIRM_MODAL_CONFIRM, this.popConfirmModal.id);
  7685. }
  7686. }
  7687. };
  7688. const _withScopeId = (n2) => (vue.pushScopeId("data-v-a73f564c"), n2 = n2(), vue.popScopeId(), n2);
  7689. const _hoisted_1 = {
  7690. key: 0,
  7691. class: ""
  7692. };
  7693. const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep" }, null, -1));
  7694. const _hoisted_3 = { class: "box calender" };
  7695. const _hoisted_4 = { class: "month" };
  7696. const _hoisted_5 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "fade" }, "历史最热", -1));
  7697. const _hoisted_6 = { class: "ca-title" };
  7698. const _hoisted_7 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "calender-header" }, [
  7699. /* @__PURE__ */ vue.createElementVNode("div", null, "日"),
  7700. /* @__PURE__ */ vue.createElementVNode("div", null, "一"),
  7701. /* @__PURE__ */ vue.createElementVNode("div", null, "二"),
  7702. /* @__PURE__ */ vue.createElementVNode("div", null, "三"),
  7703. /* @__PURE__ */ vue.createElementVNode("div", null, "四"),
  7704. /* @__PURE__ */ vue.createElementVNode("div", null, "五"),
  7705. /* @__PURE__ */ vue.createElementVNode("div", null, "六")
  7706. ], -1));
  7707. const _hoisted_8 = { class: "days" };
  7708. const _hoisted_9 = ["onClick"];
  7709. const _hoisted_10 = ["href"];
  7710. const _hoisted_11 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep" }, null, -1));
  7711. const _hoisted_12 = {
  7712. key: 0,
  7713. class: "target-user-tags p1"
  7714. };
  7715. const _hoisted_13 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "标签:", -1));
  7716. const _hoisted_14 = { class: "my-tag" };
  7717. const _hoisted_15 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  7718. const _hoisted_16 = ["onClick"];
  7719. const _hoisted_17 = {
  7720. key: 1,
  7721. class: "my-box p2",
  7722. style: { "margin-top": "2rem", "margin-bottom": "0" }
  7723. };
  7724. const _hoisted_18 = {
  7725. key: 0,
  7726. class: "flex flex-center"
  7727. };
  7728. const _hoisted_19 = {
  7729. key: 1,
  7730. class: "loaded"
  7731. };
  7732. const _hoisted_20 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "楼中楼解析完成", -1));
  7733. const _hoisted_21 = {
  7734. key: 0,
  7735. ref: "tip",
  7736. class: "pop-confirm-content"
  7737. };
  7738. const _hoisted_22 = { class: "text" };
  7739. const _hoisted_23 = { class: "options" };
  7740. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  7741. const _component_Setting = vue.resolveComponent("Setting");
  7742. const _component_TagModal = vue.resolveComponent("TagModal");
  7743. const _component_PostDetail = vue.resolveComponent("PostDetail");
  7744. const _component_Base64Tooltip = vue.resolveComponent("Base64Tooltip");
  7745. const _component_MsgModal = vue.resolveComponent("MsgModal");
  7746. const _component_NotificationModal = vue.resolveComponent("NotificationModal");
  7747. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  7748. const _component_BaseButton = vue.resolveComponent("BaseButton");
  7749. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  7750. vue.createVNode(_component_Setting, {
  7751. modelValue: $data.config,
  7752. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.config = $event),
  7753. show: $data.configModal.show,
  7754. "onUpdate:show": _cache[1] || (_cache[1] = ($event) => $data.configModal.show = $event)
  7755. }, null, 8, ["modelValue", "show"]),
  7756. vue.createVNode(_component_TagModal, {
  7757. tags: $data.tags,
  7758. "onUpdate:tags": _cache[2] || (_cache[2] = ($event) => $data.tags = $event)
  7759. }, null, 8, ["tags"]),
  7760. vue.createVNode(_component_PostDetail, {
  7761. modelValue: $data.show,
  7762. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.show = $event),
  7763. ref: "postDetail",
  7764. displayType: $data.config.commentDisplayType,
  7765. "onUpdate:displayType": _cache[4] || (_cache[4] = ($event) => $data.config.commentDisplayType = $event),
  7766. onRefresh: _cache[5] || (_cache[5] = ($event) => $options.getPostDetail($data.current)),
  7767. loading: $data.loading,
  7768. refreshLoading: $data.refreshLoading
  7769. }, null, 8, ["modelValue", "displayType", "loading", "refreshLoading"]),
  7770. vue.createVNode(_component_Base64Tooltip),
  7771. vue.createVNode(_component_MsgModal),
  7772. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "#Rightbar > .sep20" }, [
  7773. $data.calendar.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
  7774. _hoisted_2,
  7775. vue.createElementVNode("div", _hoisted_3, [
  7776. vue.createElementVNode("div", _hoisted_4, [
  7777. _hoisted_5,
  7778. vue.createElementVNode("div", _hoisted_6, [
  7779. vue.createElementVNode("i", {
  7780. class: "fa fa-arrow-left",
  7781. onClick: _cache[6] || (_cache[6] = ($event) => $options.getMonthDayInfo(-1)),
  7782. "aria-hidden": "true"
  7783. }),
  7784. vue.createElementVNode("span", null, vue.toDisplayString($data.calendar.year) + "年" + vue.toDisplayString($data.calendar.month + 1) + "月", 1),
  7785. vue.createElementVNode("i", {
  7786. class: "fa fa-arrow-right",
  7787. onClick: _cache[7] || (_cache[7] = ($event) => $options.getMonthDayInfo(1)),
  7788. "aria-hidden": "true"
  7789. })
  7790. ])
  7791. ]),
  7792. _hoisted_7,
  7793. vue.createElementVNode("div", _hoisted_8, [
  7794. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($data.calendar.dayCount + $data.calendar.firstDayWeek, (i) => {
  7795. return vue.openBlock(), vue.createElementBlock("div", {
  7796. class: vue.normalizeClass([
  7797. "day",
  7798. $data.calendar.select === `${$data.calendar.year}-${$data.calendar.month + 1}-${i - $data.calendar.firstDayWeek}` ? "active" : ""
  7799. ]),
  7800. onClick: ($event) => $data.calendar.select = `${$data.calendar.year}-${$data.calendar.month + 1}-${i - $data.calendar.firstDayWeek}`
  7801. }, [
  7802. i - $data.calendar.firstDayWeek > 0 ? (vue.openBlock(), vue.createElementBlock("a", {
  7803. key: 0,
  7804. href: `/v2hot?${$data.calendar.year}-${$data.calendar.month + 1}-${i - $data.calendar.firstDayWeek}`
  7805. }, vue.toDisplayString(i - $data.calendar.firstDayWeek > 0 ? i - $data.calendar.firstDayWeek : ""), 9, _hoisted_10)) : vue.createCommentVNode("", true)
  7806. ], 10, _hoisted_9);
  7807. }), 256))
  7808. ])
  7809. ]),
  7810. _hoisted_11
  7811. ])) : vue.createCommentVNode("", true)
  7812. ])),
  7813. vue.createVNode(_component_NotificationModal, {
  7814. modelValue: $data.notificationModal.show,
  7815. "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => $data.notificationModal.show = $event),
  7816. list: $data.notificationModal.list,
  7817. loading: $data.notificationModal.loading,
  7818. total: $data.notificationModal.total,
  7819. pages: $data.notificationModal.pages
  7820. }, null, 8, ["modelValue", "list", "loading", "total", "pages"]),
  7821. !$data.stopMe ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  7822. $options.isMember && $data.isLogin && $data.config.openTag ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12, [
  7823. _hoisted_13,
  7824. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.targetUserTags, (i) => {
  7825. return vue.openBlock(), vue.createElementBlock("span", _hoisted_14, [
  7826. _hoisted_15,
  7827. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  7828. vue.createElementVNode("i", {
  7829. class: "fa fa-trash-o remove",
  7830. onClick: ($event) => $options.removeTargetUserTag(i)
  7831. }, null, 8, _hoisted_16)
  7832. ]);
  7833. }), 256)),
  7834. vue.createElementVNode("span", {
  7835. class: "add-tag ago",
  7836. onClick: _cache[9] || (_cache[9] = (...args) => $options.addTargetUserTag && $options.addTargetUserTag(...args)),
  7837. title: "添加标签"
  7838. }, "+")
  7839. ])) : vue.createCommentVNode("", true),
  7840. $options.isPost && !$data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_17, [
  7841. $data.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_18, [
  7842. vue.createVNode(_component_BaseLoading)
  7843. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_19, [
  7844. _hoisted_20,
  7845. vue.createVNode(_component_BaseButton, {
  7846. size: "small",
  7847. onClick: $options.showPost
  7848. }, {
  7849. default: vue.withCtx(() => [
  7850. vue.createTextVNode("点击显示")
  7851. ]),
  7852. _: 1
  7853. }, 8, ["onClick"])
  7854. ]))
  7855. ])) : vue.createCommentVNode("", true)
  7856. ], 64)) : vue.createCommentVNode("", true),
  7857. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  7858. vue.createVNode(vue.Transition, null, {
  7859. default: vue.withCtx(() => [
  7860. $data.popConfirmModal.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_21, [
  7861. vue.createElementVNode("div", _hoisted_22, vue.toDisplayString($data.popConfirmModal.title), 1),
  7862. vue.createElementVNode("div", _hoisted_23, [
  7863. vue.createVNode(_component_BaseButton, {
  7864. type: "link",
  7865. size: "small",
  7866. onClick: vue.withModifiers($options.popConfirmModalCancel, ["stop"])
  7867. }, {
  7868. default: vue.withCtx(() => [
  7869. vue.createTextVNode("取消")
  7870. ]),
  7871. _: 1
  7872. }, 8, ["onClick"]),
  7873. vue.createVNode(_component_BaseButton, {
  7874. size: "small",
  7875. onClick: vue.withModifiers($options.popConfirmModalConfirm, ["stop"])
  7876. }, {
  7877. default: vue.withCtx(() => [
  7878. vue.createTextVNode("确认")
  7879. ]),
  7880. _: 1
  7881. }, 8, ["onClick"])
  7882. ])
  7883. ], 512)) : vue.createCommentVNode("", true)
  7884. ]),
  7885. _: 1
  7886. })
  7887. ]))
  7888. ], 64);
  7889. }
  7890. const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-a73f564c"]]);
  7891. let isMobile = !document.querySelector("#Rightbar");
  7892. let $section = document.createElement("section");
  7893. $section.id = "app";
  7894. function run() {
  7895. window.user = DefaultUser;
  7896. window.targetUserName = "";
  7897. window.pageType = void 0;
  7898. window.pageData = { pageNo: 1 };
  7899. window.config = getDefaultConfig();
  7900. window.isNight = $(".Night").length === 1;
  7901. window.cb = null;
  7902. window.stopMe = false;
  7903. window.isLogin = false;
  7904. window.postList = [];
  7905. window.isDeadline = dayjs().isAfter(dayjs("2024-11-26"));
  7906. window.parse = {
  7907. //解析主题内容
  7908. async parsePostContent(post, body, htmlText) {
  7909. let once = htmlText.match(/var once = "([\d]+)";/);
  7910. if (once && once[1]) {
  7911. post.once = once[1];
  7912. }
  7913. post.isReport = htmlText.includes("你已对本主题进行了报告");
  7914. let wrapper = body.find("#Main");
  7915. if (!post.title || !post.content_rendered) {
  7916. let h1 = wrapper.find("h1");
  7917. if (h1) {
  7918. post.title = h1[0].innerText;
  7919. }
  7920. }
  7921. let as = wrapper.find(".header > a");
  7922. if (as.length) {
  7923. post.node.title = as[1].innerText;
  7924. post.node.url = as[1].href;
  7925. }
  7926. let aName = wrapper.find(".header small.gray a:nth-child(1)");
  7927. if (aName.length) {
  7928. post.member.username = aName[0].innerText;
  7929. }
  7930. let spanEl = wrapper.find(".header small.gray span");
  7931. if (spanEl.length) {
  7932. post.createDateAgo = spanEl[0].innerText;
  7933. post.createDate = spanEl[0].title;
  7934. }
  7935. let avatarEl = wrapper.find(".header .avatar");
  7936. if (avatarEl.length) {
  7937. post.member.avatar_large = avatarEl[0].src;
  7938. }
  7939. let topic_buttons = body.find(".topic_buttons");
  7940. if (topic_buttons.length) {
  7941. let favoriteNode = topic_buttons.find(".tb:first");
  7942. if (favoriteNode.length) {
  7943. post.isFavorite = favoriteNode[0].innerText === "取消收藏";
  7944. }
  7945. let ignoreNode = topic_buttons.find(".tb:nth-child(3)");
  7946. if (ignoreNode.length) {
  7947. post.isIgnore = ignoreNode[0].innerText === "取消忽略";
  7948. }
  7949. let thankNode = topic_buttons.find("#topic_thank .tb");
  7950. if (!thankNode.length) {
  7951. post.isThanked = true;
  7952. }
  7953. let topic_stats = topic_buttons.find(".topic_stats");
  7954. if (topic_stats.length) {
  7955. let text = topic_stats[0].innerText;
  7956. let reg1 = text.matchAll(/([\d]+)[\s]*人收藏/g);
  7957. let collectCountReg = [...reg1];
  7958. if (collectCountReg.length) {
  7959. post.collectCount = Number(collectCountReg[0][1]);
  7960. }
  7961. reg1 = text.matchAll(/([\d]+)[\s]*likes/g);
  7962. collectCountReg = [...reg1];
  7963. if (collectCountReg.length) {
  7964. post.collectCount = Number(collectCountReg[0][1]);
  7965. }
  7966. let reg2 = text.matchAll(/([\d]+)[\s]*人感谢/g);
  7967. let thankCountReg = [...reg2];
  7968. if (thankCountReg.length) {
  7969. post.thankCount = Number(thankCountReg[0][1]);
  7970. }
  7971. let reg3 = text.matchAll(/([\d]+)[\s]*次点击/g);
  7972. let clickCountReg = [...reg3];
  7973. if (clickCountReg.length) {
  7974. post.clickCount = Number(clickCountReg[0][1]);
  7975. }
  7976. reg3 = text.matchAll(/([\d]+)[\s]*views/g);
  7977. clickCountReg = [...reg3];
  7978. if (clickCountReg.length) {
  7979. post.clickCount = Number(clickCountReg[0][1]);
  7980. }
  7981. }
  7982. }
  7983. let header = body.find(`#Main .box`).first();
  7984. let temp = header.clone();
  7985. temp.find(".topic_buttons").remove();
  7986. temp.find(".inner").remove();
  7987. temp.find(".header").remove();
  7988. functions.checkPhotoLink2Img(temp[0]);
  7989. post.headerTemplate = temp[0].innerHTML;
  7990. return post;
  7991. },
  7992. //解析OP信息
  7993. async parseOp(post) {
  7994. if (!post.member.id) {
  7995. let userRes = await fetch(location.origin + "/api/members/show.json?username=" + post.member.username);
  7996. if (userRes.status === 200) {
  7997. post.member = await userRes.json();
  7998. }
  7999. }
  8000. if (post.member.id) {
  8001. let date = new Date(post.member.created * 1e3);
  8002. let createStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
  8003. date.setHours(0);
  8004. date.setMinutes(0);
  8005. date.setSeconds(0);
  8006. date.setMilliseconds(0);
  8007. let now = /* @__PURE__ */ new Date();
  8008. now.setHours(0);
  8009. now.setMinutes(0);
  8010. now.setSeconds(0);
  8011. now.setMilliseconds(0);
  8012. let d2 = now.getTime() - date.getTime();
  8013. let isNew = d2 <= 1e3 * 60 * 60 * 24 * 15;
  8014. post.member.createDate = createStr + " 注册";
  8015. post.member.isNew = isNew;
  8016. } else {
  8017. post.member.createDate = "用户已被注销/封禁";
  8018. post.member.isNew = true;
  8019. }
  8020. return post;
  8021. },
  8022. //获取主题所有回复
  8023. async getPostAllReplies(post, body, htmlText, pageNo = 1) {
  8024. var _a, _b;
  8025. if (body.find("#no-comments-yet").length) {
  8026. return post;
  8027. }
  8028. let boxs = body.find(`#Main .box`);
  8029. let box = boxs[1];
  8030. let cells = box.querySelectorAll(".cell");
  8031. if (cells && cells.length) {
  8032. post.fr = cells[0].querySelector(".cell .fr").innerHTML;
  8033. cells = Array.from(cells);
  8034. let snow = cells[0].querySelector(".snow");
  8035. post.lastReplyDate = ((_b = (_a = snow == null ? void 0 : snow.nextSibling) == null ? void 0 : _a.nodeValue) == null ? void 0 : _b.trim()) || "";
  8036. let repliesMap = [];
  8037. if (cells[1].id) {
  8038. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(1)) });
  8039. let replyList = functions.getAllReply(repliesMap);
  8040. functions.createList(post, replyList);
  8041. return post;
  8042. } else {
  8043. let promiseList = [];
  8044. return new Promise((resolve, reject) => {
  8045. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  8046. let pages = cells[1].querySelectorAll("a.page_normal");
  8047. pages = Array.from(pages);
  8048. let url = location.origin + "/t/" + post.id;
  8049. for (let i = 0; i < pages.length; i++) {
  8050. let currentPageNo = Number(pages[i].innerText);
  8051. promiseList.push(this.fetchPostOtherPageReplies(url + "?p=" + currentPageNo, currentPageNo));
  8052. }
  8053. Promise.allSettled(promiseList).then(
  8054. (results) => {
  8055. results.filter((result) => result.status === "fulfilled").map((v) => repliesMap.push(v.value));
  8056. let replyList = functions.getAllReply(repliesMap);
  8057. functions.createList(post, replyList);
  8058. resolve(post);
  8059. }
  8060. );
  8061. });
  8062. }
  8063. }
  8064. },
  8065. //请求主题其他页的回复
  8066. fetchPostOtherPageReplies(href, pageNo) {
  8067. return new Promise((resolve) => {
  8068. $.get(href).then((res) => {
  8069. let s = res.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  8070. let box = $(s[0]).find("#Main .box")[1];
  8071. let cells = box.querySelectorAll(".cell");
  8072. cells = Array.from(cells);
  8073. resolve({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  8074. }).catch((r2) => {
  8075. if (r2.status === 403) {
  8076. functions.cbChecker({ type: "restorePost", value: null });
  8077. }
  8078. });
  8079. });
  8080. },
  8081. //解析页面的回复
  8082. parsePageReplies(nodes) {
  8083. let replyList = [];
  8084. nodes.forEach((node, index) => {
  8085. if (!node.id)
  8086. return;
  8087. let item = {
  8088. level: 0,
  8089. thankCount: 0,
  8090. replyCount: 0,
  8091. isThanked: false,
  8092. isOp: false,
  8093. isDup: false,
  8094. id: node.id.replace("r_", "")
  8095. };
  8096. let reply_content = node.querySelector(".reply_content");
  8097. functions.checkPhotoLink2Img(reply_content);
  8098. item.reply_content = reply_content.innerHTML;
  8099. item.reply_text = reply_content.textContent;
  8100. let { users, floor } = this.parseReplyContent(item.reply_content);
  8101. item.hideCallUserReplyContent = item.reply_content;
  8102. if (users.length === 1) {
  8103. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(?:<ul [\s\S]+<\/ul>)?(\s#[\d]+)?\s(<br>)?/, () => "");
  8104. }
  8105. item.replyUsers = users;
  8106. item.replyFloor = floor;
  8107. let ago = node.querySelector(".ago");
  8108. item.date = ago.textContent;
  8109. let userNode = node.querySelector("strong a");
  8110. item.username = userNode.textContent;
  8111. let avatar = node.querySelector("td img");
  8112. item.avatar = avatar.src;
  8113. let no = node.querySelector(".no");
  8114. item.floor = Number(no.textContent);
  8115. let thank_area = node.querySelector(".thank_area");
  8116. if (thank_area) {
  8117. item.isThanked = thank_area.classList.contains("thanked");
  8118. }
  8119. let small = node.querySelector(".small");
  8120. if (small) {
  8121. item.thankCount = Number(small.textContent);
  8122. }
  8123. let op = node.querySelector(".op");
  8124. if (op) {
  8125. item.isOp = true;
  8126. }
  8127. let mod = node.querySelector(".mod");
  8128. if (mod) {
  8129. item.isMod = true;
  8130. }
  8131. replyList.push(item);
  8132. });
  8133. return replyList;
  8134. },
  8135. //解析回复内容,解析出@用户,回复楼层。用于后续生成嵌套楼层
  8136. parseReplyContent(str) {
  8137. if (!str)
  8138. return;
  8139. let users = [];
  8140. let getUsername = (userStr) => {
  8141. users.push(userStr);
  8142. };
  8143. let userReg = /@<a href="\/member\/([^'" ]+)/g;
  8144. let has = str.matchAll(userReg);
  8145. let res2 = [...has];
  8146. if (res2.length > 1) {
  8147. res2.map((item) => {
  8148. getUsername(item[1]);
  8149. });
  8150. }
  8151. if (res2.length === 1) {
  8152. getUsername(res2[0][1]);
  8153. }
  8154. let floor = -1;
  8155. if (users.length === 1) {
  8156. let floorReg = /@<a href="\/member\/[\s\S]+?<\/a>(?:<ul [\s\S]+<\/ul>)?[\s]+#([\d]+)/g;
  8157. let hasFloor = str.matchAll(floorReg);
  8158. let res = [...hasFloor];
  8159. if (res.length) {
  8160. floor = Number(res[0][1]);
  8161. }
  8162. }
  8163. return { users, floor };
  8164. },
  8165. //获取主题详情
  8166. async getPostDetail(post, body, htmlText, pageNo = 1) {
  8167. post = await this.parsePostContent(post, body, htmlText);
  8168. return await this.getPostAllReplies(post, body, htmlText, pageNo);
  8169. },
  8170. //解析页面主题列表
  8171. parsePagePostList(list, box) {
  8172. list.forEach((itemDom) => {
  8173. let item_title = itemDom.querySelector(".item_title");
  8174. if (!item_title)
  8175. return;
  8176. let item = getDefaultPost();
  8177. itemDom.classList.add("post-item");
  8178. let a = item_title.querySelector("a");
  8179. let { href, id } = functions.parseA(a);
  8180. item.id = String(Number(id));
  8181. a.href = item.href = href;
  8182. item.url = location.origin + "/api/topics/show.json?id=" + item.id;
  8183. itemDom.classList.add(`id_${id}`);
  8184. itemDom.dataset["href"] = href;
  8185. let td = itemDom.querySelector("td:nth-child(4)");
  8186. if (!td) {
  8187. td = itemDom.querySelector("td:nth-child(2)");
  8188. }
  8189. td.style.position = "relative";
  8190. let toggle = document.createElement("div");
  8191. toggle.dataset["id"] = item.id;
  8192. toggle.classList.add("toggle");
  8193. toggle.innerText = "预览";
  8194. td.append(toggle);
  8195. if (window.config.viewType === "card") {
  8196. window.postList.push(item);
  8197. }
  8198. });
  8199. localStorage.setItem("d", "");
  8200. if (window.pageType === PageType.Home) {
  8201. const a = () => {
  8202. let d2;
  8203. if (window.user.username) {
  8204. d2 = $(window.atob("LnYycC1ob3Zlci1idG4=")).length;
  8205. } else {
  8206. d2 = $(window.atob("LnYycC1mb290ZXI=")).length;
  8207. }
  8208. if (d2 !== 0) {
  8209. window.stopMe = true;
  8210. localStorage.setItem("d", "1");
  8211. functions.cbChecker({ type: "syncData" });
  8212. } else {
  8213. localStorage.setItem("d", "");
  8214. }
  8215. };
  8216. a();
  8217. setTimeout(a, 1e3);
  8218. setTimeout(a, 2e3);
  8219. setTimeout(a, 3e3);
  8220. setTimeout(a, 5e3);
  8221. setTimeout(a, 1e4);
  8222. setTimeout(a, 15e3);
  8223. }
  8224. const setF = (res) => {
  8225. let rIndex = window.postList.findIndex((w) => w.id == res.id);
  8226. if (rIndex > -1) {
  8227. window.postList[rIndex] = Object.assign(window.postList[rIndex], res);
  8228. functions.cbChecker({ type: "syncList" });
  8229. }
  8230. let itemDom = box.querySelector(`.id_${res.id}`);
  8231. itemDom.classList.add("preview");
  8232. if (res.content_rendered) {
  8233. functions.appendPostContent(res, itemDom);
  8234. }
  8235. };
  8236. if (window.config.viewType === "card" && !window.stopMe) {
  8237. let cacheDataStr = localStorage.getItem("cacheData");
  8238. let cacheData = [];
  8239. if (cacheDataStr) {
  8240. cacheData = JSON.parse(cacheDataStr);
  8241. let now = Date.now();
  8242. cacheData = cacheData.filter((v) => {
  8243. return v.created > now / 1e3 - 60 * 60 * 24 * 3;
  8244. });
  8245. }
  8246. let fetchIndex = 0;
  8247. for (let i = 0; i < window.postList.length; i++) {
  8248. let item = window.postList[i];
  8249. let rItem = cacheData.find((w) => w.id == item.id);
  8250. if (rItem) {
  8251. rItem.href = item.href;
  8252. setF(rItem);
  8253. } else {
  8254. fetchIndex++;
  8255. setTimeout(() => {
  8256. $.get(item.url).then((v) => {
  8257. if (v && v.length) {
  8258. let res = getDefaultPost(v[0]);
  8259. res.href = item.href;
  8260. cacheData.push(res);
  8261. localStorage.setItem("cacheData", JSON.stringify(cacheData));
  8262. setF(res);
  8263. }
  8264. });
  8265. }, fetchIndex < 4 ? 0 : (fetchIndex - 4) * 1e3);
  8266. }
  8267. }
  8268. }
  8269. },
  8270. //创建记事本子条目
  8271. async createNoteItem(itemName) {
  8272. return new Promise(async (resolve) => {
  8273. if (!window.isLogin)
  8274. return resolve(null);
  8275. let data = new FormData();
  8276. data.append("content", itemName);
  8277. data.append("parent_id", 0);
  8278. data.append("syntax", 0);
  8279. let apiRes = await fetch(`${location.origin}/notes/new`, { method: "post", body: data });
  8280. if (apiRes.redirected && apiRes.status === 200) {
  8281. resolve(apiRes.url.substr(-5));
  8282. return;
  8283. }
  8284. resolve(null);
  8285. });
  8286. },
  8287. //编辑记事本子条目
  8288. async editNoteItem(val, id) {
  8289. if (!window.isLogin)
  8290. return;
  8291. if (!id)
  8292. return;
  8293. let data = new FormData();
  8294. data.append("content", val);
  8295. data.append("syntax", 0);
  8296. let apiRes = await fetch(`${location.origin}/notes/edit/${id}`, {
  8297. method: "post",
  8298. body: data
  8299. });
  8300. return apiRes.redirected && apiRes.status === 200;
  8301. },
  8302. //标签操作
  8303. async saveTags(val) {
  8304. if (!window.isLogin)
  8305. return;
  8306. for (const [key, value] of Object.entries(val)) {
  8307. if (!value.length)
  8308. delete val[key];
  8309. }
  8310. return await this.editNoteItem(window.user.tagPrefix + JSON.stringify(val), window.user.tagsId);
  8311. },
  8312. //imgur图片删除hash操作
  8313. async saveImgurList(val) {
  8314. if (!window.isLogin)
  8315. return;
  8316. return;
  8317. }
  8318. };
  8319. function initMonkeyMenu() {
  8320. try {
  8321. _GM_registerMenuCommand("脚本设置", () => {
  8322. functions.cbChecker({ type: "openSetting" });
  8323. });
  8324. _GM_registerMenuCommand("仓库地址", () => {
  8325. functions.openNewTab(DefaultVal.git, true);
  8326. });
  8327. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  8328. } catch (e2) {
  8329. console.error("无法使用Tampermonkey");
  8330. }
  8331. }
  8332. function initStyle() {
  8333. if (window.isNight) {
  8334. document.documentElement.classList.add("dark");
  8335. }
  8336. let style2 = `
  8337. html, body {
  8338. font-size: 62.5%;
  8339. }
  8340. :root{
  8341. --box-border-radius:8px;
  8342. }
  8343. .page_current, .page_normal {
  8344. --box-border-radius: 5px;
  8345. padding: .6rem 0.8rem!important;
  8346. }
  8347. .box{
  8348. box-shadow:rgba(0, 0, 0, 0.08) 0px 4px 12px;
  8349. }
  8350. #Tabs{
  8351. border-top-left-radius: var(--box-border-radius) !important;
  8352. border-top-right-radius: var(--box-border-radius) !important;
  8353. }
  8354. #Main .cell .count_livid {
  8355. font-size: 14px;
  8356. font-weight: bold;
  8357. padding: 3px 10px;
  8358. border-radius: 5px;
  8359. }
  8360.  
  8361. #Wrapper {
  8362. height: unset !important;
  8363. width: unset !important;
  8364. }
  8365.  
  8366. #Wrapper > .content {
  8367. height: unset !important;
  8368. width: unset !important;
  8369. max-width:1100px !important;
  8370. }
  8371.  
  8372. ${location.pathname.includes("wow") || location.pathname.includes("tokyo") ? "" : `
  8373. .post-item {
  8374. background: white;
  8375. }
  8376. `}
  8377.  
  8378. .post-item > .post-content {
  8379. height: 0;
  8380. margin-top: 0;
  8381. }
  8382.  
  8383. .post-item:hover .toggle {
  8384. display: flex;
  8385. }
  8386.  
  8387. .toggle {
  8388. position: absolute;
  8389. right: ${window.config.viewType === "simple" ? "5rem" : 0};
  8390. top: ${window.config.viewType === "simple" ? 0 : "0.5rem"};
  8391. width: 5rem;
  8392. height: 100%;
  8393. display: flex;
  8394. justify-content: flex-end;
  8395. align-items: flex-end;
  8396. cursor: pointer;
  8397. font-size: 1.2rem;
  8398. color: var(--link-color);
  8399. display: none;
  8400. padding-right: 1rem;
  8401. }
  8402.  
  8403. .preview {
  8404. margin: 1rem 0;
  8405. border: 1px solid transparent;
  8406. border-radius: var(--box-border-radius);
  8407. cursor: pointer;
  8408. }
  8409.  
  8410. .preview:hover {
  8411. border: 1px solid #c8c8c8;
  8412. }
  8413.  
  8414. .preview > .post-content {
  8415. height: unset !important;
  8416. margin-top: 0.5rem !important;
  8417. }
  8418.  
  8419. .preview > .post-content.show-all {
  8420. max-height: unset;
  8421. -webkit-mask-image:none;
  8422. }
  8423.  
  8424. .preview .topic-link:link {
  8425. color: black !important;
  8426. }
  8427.  
  8428. .post-content {
  8429. margin-top: 0.5rem;
  8430. display: block;
  8431. max-height: 30rem;
  8432. overflow: hidden;
  8433. text-decoration: unset !important;
  8434. line-break: anywhere;
  8435. -webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);
  8436. }
  8437.  
  8438. .show-more {
  8439. display: none;
  8440. }
  8441.  
  8442. .preview > .show-more {
  8443. font-size: 1.3rem;
  8444. text-align: right;
  8445. height: 3rem;
  8446. display: flex;
  8447. align-items: center;
  8448. justify-content: center;
  8449. position: relative;
  8450. z-index: 9;
  8451. }
  8452.  
  8453. .post-content:visited {
  8454. color: #afb9c1 !important;
  8455. }
  8456.  
  8457. .post-content:link {
  8458. color: #494949;
  8459. }
  8460. ${location.href.includes("wow") ? "" : `
  8461. .Night .post-item {
  8462. background: #18222d !important;
  8463. }
  8464. `}
  8465.  
  8466. .Night .preview {
  8467. border: 1px solid #3b536e;
  8468. }
  8469.  
  8470. .Night .preview > .post-content:link {
  8471. color: #d1d5d9;
  8472. }
  8473.  
  8474. .Night .preview > .post-content:visited {
  8475. color: #393f4e !important;
  8476. }
  8477. .Night .preview .topic-link:link {
  8478. color: #c0dbff !important;
  8479. }
  8480. ${window.config.viewType === "simple" ? `
  8481. ${window.pageType !== PageType.Member ? `
  8482. .item table tr td:first-child{display:none;}
  8483. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  8484. .item table tr td .sep5{display:none;}
  8485. .item table tr td .topic_info{display:none;}
  8486. .item {border-bottom:none;}
  8487. .avatar,#avatar{display:none;}
  8488. ` : ""}
  8489. #Logo {background-image:url('https://i.imgur.com/i9VgUtM.png');}
  8490. .bigger a, .top:nth-last-child(5){color: transparent!important;text-shadow: #b0b0b0 0 0 6px;user-select: none;}
  8491. // .bigger a:before,.top:nth-last-child(5):before{content:'Mona Lisa';position: absolute;background: white;}
  8492. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  8493. ` : ""}
  8494.  
  8495. ${window.config.customBgColor ? `#Wrapper {
  8496. background: ${window.config.customBgColor} !important;
  8497. background-image: unset !important;
  8498. }` : ""}
  8499. .top{
  8500. position:relative;
  8501. }
  8502. .new{
  8503. position: absolute;
  8504. background: red;
  8505. font-size: 10px;
  8506. border-radius: 4px;
  8507. padding: 0px 2px;
  8508. color: white;
  8509. right: -9px;
  8510. top: -3px;
  8511. }
  8512. /*解决hdr头像太亮的问题*/
  8513. img{filter: brightness(0.95) contrast(0.95) saturate(0.95);}
  8514.  
  8515. }
  8516. `;
  8517. let addStyle2 = document.createElement("style");
  8518. addStyle2.rel = "stylesheet";
  8519. addStyle2.type = "text/css";
  8520. addStyle2.innerHTML = style2;
  8521. window.document.head.append(addStyle2);
  8522. }
  8523. function qianDao() {
  8524. let timeNow = (/* @__PURE__ */ new Date()).getUTCFullYear() + "/" + ((/* @__PURE__ */ new Date()).getUTCMonth() + 1) + "/" + (/* @__PURE__ */ new Date()).getUTCDate();
  8525. if (window.pageType === PageType.Home) {
  8526. let qiandao2 = document.querySelector('.box .inner a[href="/mission/daily"]');
  8527. if (qiandao2) {
  8528. qianDao_(qiandao2, timeNow);
  8529. } else if (document.getElementById("gift_v2excellent")) {
  8530. document.getElementById("gift_v2excellent").click();
  8531. localStorage.setItem("menu_clockInTime", timeNow);
  8532. } else
  8533. ;
  8534. } else {
  8535. let timeOld = localStorage.getItem("menu_clockInTime");
  8536. if (!timeOld || timeOld != timeNow) {
  8537. qianDaoStatus_(timeNow);
  8538. }
  8539. }
  8540. }
  8541. function qianDao_(qiandao2, timeNow) {
  8542. let url = location.origin + "/mission/daily/redeem?" + RegExp("once\\=(\\d+)").exec(document.querySelector("div#Top .tools, #menu-body").innerHTML)[0];
  8543. $.get(url).then((r2) => {
  8544. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  8545. let html = $(bodyText[0]);
  8546. if (html.find("li.fa.fa-ok-sign").length) {
  8547. html = html.find("#Main").text().match(/已连续登录 (\d+?) 天/)[0];
  8548. localStorage.setItem("menu_clockInTime", timeNow);
  8549. console.info("[V2Next] 自动签到完成!");
  8550. if (qiandao2) {
  8551. qiandao2.textContent = `自动签到完成!${html}`;
  8552. qiandao2.href = "javascript:void(0);";
  8553. }
  8554. } else {
  8555. console.warn("[V2Next] 自动签到失败!请关闭其他插件或脚本。如果连续几天都签到失败,请联系作者解决!");
  8556. if (qiandao2)
  8557. qiandao2.textContent = "自动签到失败!请尝试手动签到!";
  8558. }
  8559. });
  8560. }
  8561. function qianDaoStatus_(timeNow) {
  8562. $.get(location.origin + "/mission/daily").then((r2) => {
  8563. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  8564. let html = $(bodyText[0]);
  8565. if (html.find('input[value^="领取"]').length) {
  8566. qianDao_(null, timeNow);
  8567. } else {
  8568. console.info("[V2Next] 已经签过到了。");
  8569. localStorage.setItem("menu_clockInTime", timeNow);
  8570. }
  8571. });
  8572. }
  8573. function getNoteItemContent(id, prefix) {
  8574. return new Promise((resolve, reject) => {
  8575. $.get(location.origin + "/notes/edit/" + id).then((r2) => {
  8576. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  8577. let body = $(bodyText[0]);
  8578. let text = body.find(".note_editor").text();
  8579. if (text === prefix) {
  8580. resolve({});
  8581. } else {
  8582. let tagJson = text.substring(prefix.length);
  8583. try {
  8584. resolve(JSON.parse(tagJson));
  8585. } catch (e2) {
  8586. resolve({});
  8587. }
  8588. }
  8589. });
  8590. });
  8591. }
  8592. async function initNoteData() {
  8593. $.get(location.origin + "/notes").then(async (r2) => {
  8594. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  8595. let body = $(bodyText[0]);
  8596. let items = body.find("#Main .box .note_item_title a");
  8597. if (window.config.openTag) {
  8598. let tagItems2 = Array.from(items).filter((v) => v.innerText.includes(window.user.tagPrefix));
  8599. if (tagItems2.length) {
  8600. window.user.tagsId = tagItems2[0].href.substr(-5);
  8601. window.user.tags = await getNoteItemContent(window.user.tagsId, window.user.tagPrefix);
  8602. } else {
  8603. let r22 = await window.parse.createNoteItem(window.user.tagPrefix);
  8604. r22 && (window.user.tagsId = r22);
  8605. }
  8606. }
  8607. let tagItems = Array.from(items).filter((v) => v.innerText.includes(window.user.configPrefix));
  8608. if (tagItems.length) {
  8609. window.user.configNoteId = tagItems[0].href.substr(-5);
  8610. let config2 = await getNoteItemContent(window.user.configNoteId, window.user.configPrefix);
  8611. window.config = functions.deepAssign(window.config, config2);
  8612. } else {
  8613. let r22 = await window.parse.createNoteItem(window.user.configPrefix);
  8614. r22 && (window.user.configNoteId = r22);
  8615. }
  8616. functions.cbChecker({ type: "syncData" });
  8617. functions.cbChecker({ type: "getConfigSuccess" });
  8618. });
  8619. }
  8620. function addSettingText() {
  8621. let app = $(`<a href="${DefaultVal.mobileScript}" target='_blank' class="top"><i class="fa fa-android" aria-hidden="true"></i></a>`);
  8622. $(".tools").prepend(app);
  8623. let setting = $(`<a href="/" class="top v2next-setting"><span>脚本设置</span></a>`);
  8624. setting.on("click", function(e2) {
  8625. functions.stopEvent(e2);
  8626. functions.cbChecker({ type: "openSetting" });
  8627. });
  8628. $(".tools").prepend(setting);
  8629. }
  8630. async function init() {
  8631. let top2 = document.querySelector(".tools .top:nth-child(2)");
  8632. if (top2 && top2.textContent !== "注册") {
  8633. window.isLogin = true;
  8634. window.user.username = top2.textContent;
  8635. window.user.avatar = $("#Rightbar .box .avatar").attr("src");
  8636. }
  8637. functions.initConfig();
  8638. let box;
  8639. let list;
  8640. let last;
  8641. let headerWrap;
  8642. let { pageData, pageType, username } = functions.checkPageType();
  8643. window.pageType = pageType;
  8644. window.pageData = pageData;
  8645. window.targetUserName = username;
  8646. initStyle();
  8647. switch (window.pageType) {
  8648. case PageType.Node:
  8649. box = document.querySelectorAll("#Wrapper #Main .box");
  8650. try {
  8651. headerWrap = $('<div class="post-item"></div>');
  8652. if (window.config.viewType === "card")
  8653. headerWrap[0].classList.add("preview");
  8654. $(box[1]).prepend(headerWrap);
  8655. $(box[1]).children().slice(1, 3).each(function() {
  8656. if (this.classList.contains("cell")) {
  8657. headerWrap.append(this);
  8658. }
  8659. });
  8660. headerWrap = $('<div class="post-item"></div>');
  8661. if (window.config.viewType === "card")
  8662. headerWrap[0].classList.add("preview");
  8663. $(box[1]).append(headerWrap);
  8664. $(box[1]).children().slice(2).each(function() {
  8665. if (this.classList.contains("cell")) {
  8666. headerWrap.append(this);
  8667. }
  8668. });
  8669. box[1].style.boxShadow = "unset";
  8670. box[1].style.background = "unset";
  8671. box[1].style.overflow = "hidden";
  8672. } catch (e2) {
  8673. console.log("PageType-Node解析报错了", e2);
  8674. }
  8675. let topics = box[1].querySelector("#TopicsNode");
  8676. list = topics.querySelectorAll(".cell");
  8677. list[0].before($section);
  8678. window.parse.parsePagePostList(list, box[1]);
  8679. break;
  8680. case PageType.Changes:
  8681. case PageType.Home:
  8682. box = document.querySelector("#Wrapper #Main .box");
  8683. try {
  8684. headerWrap = $('<div class="post-item"></div>');
  8685. if (window.config.viewType === "card")
  8686. headerWrap[0].classList.add("preview");
  8687. $(box).prepend(headerWrap);
  8688. $(box).children().slice(1, 3).each(function() {
  8689. if (!this.classList.contains("item")) {
  8690. headerWrap.append(this);
  8691. }
  8692. });
  8693. if (window.isDeadline && $(".tab_current").text() == "最热") {
  8694. headerWrap.append($(`<div class="cell" id="SecondaryTabs"><div class="fr"><a href="/v2hot?3">3天最热</a> &nbsp; &nbsp; <a href="/v2hot?7">7天最热</a> &nbsp; &nbsp; <a href="/v2hot?30">30天最热</a> &nbsp; &nbsp; <a href="/v2hot?setting"><i class="fa fa-calendar" aria-hidden="true"></i></a></div><a href="/v2hot?-1">昨天最热</a> &nbsp; &nbsp; <a href="/v2hot?-2">前天最热</a> &nbsp; &nbsp; </div>`));
  8695. }
  8696. last = $(box).children().last();
  8697. last.addClass("cell post-item");
  8698. if (window.config.viewType === "card")
  8699. last[0].classList.add("preview");
  8700. box.style.boxShadow = "unset";
  8701. box.style.background = "unset";
  8702. box.style.overflow = "hidden";
  8703. } catch (e2) {
  8704. console.log("PageType-Home解析报错了", e2);
  8705. }
  8706. list = box.querySelectorAll(".item");
  8707. list[0].before($section);
  8708. window.parse.parsePagePostList(list, box);
  8709. break;
  8710. case PageType.Post:
  8711. let d2 = localStorage.getItem("d");
  8712. if (d2) {
  8713. window.stopMe = true;
  8714. functions.cbChecker({ type: "syncData" });
  8715. return;
  8716. }
  8717. box = document.querySelector("#Wrapper #Main .box");
  8718. box.after($section);
  8719. let r2 = await functions.checkPostReplies(window.pageData.id, false);
  8720. if (r2) {
  8721. window.stopMe = true;
  8722. functions.cbChecker({ type: "syncData" });
  8723. functions.cbChecker({ type: "warningNotice", value: "由于回复数量较多,脚本已停止解析楼中楼" });
  8724. return;
  8725. }
  8726. if (window.config.postWidth) {
  8727. let Main = $("#Main");
  8728. Main.css({
  8729. "width": window.config.postWidth,
  8730. margin: "unset"
  8731. });
  8732. $("#Wrapper > .content").css({
  8733. "max-width": "unset",
  8734. display: "flex",
  8735. "justify-content": "center",
  8736. gap: "20px"
  8737. });
  8738. Main.after($("#Rightbar"));
  8739. }
  8740. let post = getDefaultPost({ id: window.pageData.id });
  8741. let body = $(document.body);
  8742. let htmlText = document.documentElement.outerHTML;
  8743. window.parse.parsePostContent(
  8744. post,
  8745. body,
  8746. htmlText
  8747. ).then(async (res) => {
  8748. await functions.cbChecker({ type: "postContent", value: res });
  8749. await window.parse.parseOp(res);
  8750. });
  8751. window.parse.getPostAllReplies(
  8752. post,
  8753. body,
  8754. htmlText,
  8755. window.pageData.pageNo
  8756. ).then(async (res1) => {
  8757. await functions.cbChecker({ type: "postReplies", value: res1 });
  8758. });
  8759. break;
  8760. case PageType.Member:
  8761. box = document.querySelectorAll("#Wrapper #Main .box");
  8762. if (location.pathname.includes("/replies")) {
  8763. box[0].after($section);
  8764. } else if (location.pathname.includes("/topics")) {
  8765. box[0].after($section);
  8766. } else {
  8767. if (window.config.openTag) {
  8768. box[0].style.borderBottom = "none";
  8769. box[0].style["border-bottom-left-radius"] = "0";
  8770. box[0].style["border-bottom-right-radius"] = "0";
  8771. }
  8772. try {
  8773. headerWrap = $('<div class="post-item"></div>');
  8774. if (window.config.viewType === "card")
  8775. headerWrap[0].classList.add("preview");
  8776. $(box[1]).prepend(headerWrap);
  8777. $(box[1]).children().slice(1, 2).each(function() {
  8778. if (!this.classList.contains("item")) {
  8779. headerWrap.append(this);
  8780. }
  8781. });
  8782. last = $(box[1]).children().last();
  8783. last.addClass("cell post-item");
  8784. if (window.config.viewType === "card")
  8785. last[0].classList.add("preview");
  8786. box[1].style.boxShadow = "unset";
  8787. box[1].style.background = "unset";
  8788. box[1].style.overflow = "hidden";
  8789. } catch (e2) {
  8790. console.log("PageType-Member解析报错了", e2);
  8791. }
  8792. list = box[1].querySelectorAll(".cell");
  8793. box[0].after($section);
  8794. window.parse.parsePagePostList(list, box[1]);
  8795. }
  8796. break;
  8797. default:
  8798. window.stopMe = true;
  8799. functions.cbChecker({ type: "syncData" });
  8800. console.error("未知页面");
  8801. break;
  8802. }
  8803. if (window.isLogin) {
  8804. initNoteData();
  8805. try {
  8806. if (window.config.autoSignin)
  8807. qianDao();
  8808. } catch (e2) {
  8809. console.log("签到失败");
  8810. }
  8811. }
  8812. addSettingText();
  8813. initMonkeyMenu();
  8814. window.addEventListener("error", (e2) => {
  8815. let dom = e2.target;
  8816. let originImgUrl = dom.getAttribute("originUrl");
  8817. if (originImgUrl) {
  8818. let a = document.createElement("a");
  8819. a.href = originImgUrl;
  8820. a.setAttribute("notice", "此标签由v2ex超级增强脚本转换图片失败后恢复");
  8821. a.innerText = originImgUrl;
  8822. a.target = "_blank";
  8823. dom.parentNode.replaceChild(a, dom);
  8824. }
  8825. }, true);
  8826. }
  8827. window.canParseV2exPage = !window.location.search.includes("script");
  8828. if (window.canParseV2exPage) {
  8829. init();
  8830. } else {
  8831. let box = document.querySelector("#Wrapper #Main .box");
  8832. box.after($section);
  8833. window.stopMe = true;
  8834. functions.cbChecker({ type: "syncData" });
  8835. if (window.location.search.includes("script=0")) {
  8836. functions.cbChecker({ type: "warningNotice", value: "脚本无法查看此主题,已为您单独打开此主题" });
  8837. }
  8838. if (window.location.search.includes("script=1")) {
  8839. functions.cbChecker({ type: "warningNotice", value: "由于回复数量较多,已为您单独打开此主题并停止解析楼中楼" });
  8840. }
  8841. }
  8842. }
  8843. if (!isMobile) {
  8844. console.log("V2EX PC端");
  8845.  
  8846. (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-size:1.2rem;font-weight:700;color:#e02a2a}.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:.5rem;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;--color-top-reply-wrap-bg: #f2f3f5;--color-top-reply-wrap-line: #d2d2d2}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;--color-top-reply-wrap-bg: #212f3e;--color-top-reply-wrap-line: #3b536d}html[data-v-e7c0fbef],body[data-v-e7c0fbef]{font-size:62.5%}.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:.7ex;text-decoration:underline 1px}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:.2rem}.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%;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:1001;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}.pop-confirm-content[data-v-e7c0fbef]{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:1003}.pop-confirm-content .text[data-v-e7c0fbef]{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-e7c0fbef]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}img[data-v-e7c0fbef]{max-width:100%}.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%}.display-type[data-v-e4f684be]{height:3rem;padding:0 .3rem;background:var(--color-sp-btn-bg);border-radius:1rem;display:flex;font-size:1.4rem;align-items:center;color:#a9a9a9}.display-type .type[data-v-e4f684be]{border-radius:.8rem;padding:0 1.3rem;height:2.8rem;align-items:center;display:flex;position:relative;cursor:pointer}.display-type .type.active[data-v-e4f684be]{background:var(--color-second-bg);color:var(--color-font-pure);box-shadow:0 0 6px 0 var(--color-tooltip-shadow)}.display-type .type-list[data-v-e4f684be]{position:absolute;background:var(--color-sp-btn-bg);right:0;top:3rem;font-size:1.4rem;box-shadow:0 0 6px 0 var(--color-tooltip-shadow);border-radius:.6rem;z-index:9;color:var(--color-font)}.display-type .type-list .item[data-v-e4f684be]{word-break:keep-all;padding:.8rem 1rem;cursor:pointer}.display-type .type-list .item.active[data-v-e4f684be],.display-type .type-list .item[data-v-e4f684be]:hover{color:var(--color-font-pure)}.display-type svg[data-v-e4f684be]{width:1.5rem}.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)}.setting-modal .modal-root[data-v-386b43d0]{z-index:9;background:var(--color-main-bg);border-radius:1rem;font-size:1.4rem;overflow:hidden;color:var(--color-font-pure)}.setting-modal .modal-root .modal-header[data-v-386b43d0]{padding:1.4rem;display:flex;justify-content:center;position:relative}.setting-modal .modal-root .modal-header .title[data-v-386b43d0]{font-size:2.2rem;text-align:left;margin-bottom:0}.setting-modal .modal-root .modal-header svg[data-v-386b43d0]{position:absolute;right:1rem;cursor:pointer;font-size:2.6rem}.setting-modal .modal-root .body[data-v-386b43d0]{width:60rem}.setting-modal .modal-root .body .modal-content[data-v-386b43d0]{background:var(--color-second-bg);flex:1;height:100%;box-sizing:border-box;padding:1rem 1rem 1rem 2rem;font-size:1.6rem;text-align:left;line-height:1.6}.setting-modal .modal-root .body .btns[data-v-386b43d0]{margin:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1.5rem;font-size:1.4rem}.setting-modal .modal-root[data-v-29d88199]{z-index:9;background:var(--color-main-bg);border-radius:1rem;font-size:1.4rem;overflow:hidden;color:var(--color-font-pure)}.setting-modal .modal-root .modal-header[data-v-29d88199]{padding:2.4rem;display:flex;justify-content:space-between}.setting-modal .modal-root .modal-header .title[data-v-29d88199]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.setting-modal .modal-root .modal-header svg[data-v-29d88199]{cursor:pointer;font-size:2.6rem}.setting-modal .modal-root .body[data-v-29d88199]{width:45vw;height:70vh;display:flex}.setting-modal .modal-root .body .left[data-v-29d88199]{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-29d88199]{padding:1rem 2rem;display:flex;flex-direction:column;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab[data-v-29d88199]{cursor:pointer;padding:1rem 3rem;border-radius:.8rem;display:flex;align-items:center;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab.active[data-v-29d88199]{background:var(--color-item-bg)}.setting-modal .modal-root .body .left .icons[data-v-29d88199]{display:flex;gap:1rem;margin-bottom:2rem;font-size:2.4rem}.setting-modal .modal-root .body .modal-content[data-v-29d88199]{background:var(--color-second-bg);flex:1;height:100%;box-sizing:border-box;padding:1rem 1rem 1rem 2rem;border-radius:1rem;display:flex}.setting-modal .modal-root .body .modal-content .scroll[data-v-29d88199]{flex:1;padding-right:1rem;overflow:auto}.setting-modal .modal-root .body .modal-content .scroll .row[data-v-29d88199]{min-height:5rem;display:flex;justify-content:space-between;align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper[data-v-29d88199]{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-29d88199]{text-align:right;font-size:1.4rem;color:gray}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key[data-v-29d88199]{align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key input[data-v-29d88199]{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-29d88199]{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-29d88199]{font-size:1.8rem}.setting-modal .modal-root .body .modal-content .scroll .desc[data-v-29d88199]{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-29d88199]{text-align:start;font-size:1.6rem;padding-bottom:10rem}.setting-modal .modal-root .body .modal-content .scroll .line[data-v-29d88199]{border-bottom:1px solid #c4c3c3}.sub-content[data-v-29d88199]{padding:0 2rem 1rem;border-radius:1rem;background:#f3f3f3;margin-bottom:1rem}.log[data-v-29d88199]{position:relative;text-align:left;margin-bottom:20px;padding-left:20px;font-size:16px;color:#6495ed;text-decoration:underline}.Author[data-v-64aa1930]{display:flex;align-items:center;justify-content:space-between;font-size:1.2rem;position:relative}.Author.expand[data-v-64aa1930]{margin-bottom:0}.Author .Author-left[data-v-64aa1930]{display:flex;align-items:center;max-width:65%;word-break:break-all}.Author .Author-left .username[data-v-64aa1930]{font-size:1.4rem;margin-right:.6rem}.Author .Author-left .expand-icon[data-v-64aa1930]{cursor:pointer;margin-right:.6rem;width:2rem;height:2rem;transform:rotate(90deg)}.Author .Author-left .avatar[data-v-64aa1930]{margin-right:.8rem;display:flex}.Author .Author-left .avatar img[data-v-64aa1930]{width:2.8rem;height:2.8rem;border-radius:.4rem}.Author .Author-left .texts[data-v-64aa1930]{flex:1}.Author .Author-left .owner[data-v-64aa1930]{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:.6rem;transform:scale(.8)}.Author .Author-left .dup[data-v-64aa1930]{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:.6rem;transform:scale(.8)}.Author .Author-left .mod[data-v-64aa1930]{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:.6rem}.Author:hover .add-tag[data-v-64aa1930]{display:inline-block}.Author .Author-right[data-v-64aa1930]{position:absolute;right:0;display:flex;align-items:center}.Author .Author-right .toolbar[data-v-64aa1930]{display:flex;align-items:center;color:var(--color-gray);opacity:0;gap:.2rem}.Author .Author-right .toolbar[data-v-64aa1930]:hover{opacity:1}.post-editor-wrapper[data-v-85e09b4e]{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-85e09b4e]{border:1px solid var(--color-line)}.post-editor-wrapper.reply-post.isFocus .post-editor[data-v-85e09b4e]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment[data-v-85e09b4e]{border-radius:var(--box-border-radius);overflow:hidden;border:1px solid var(--color-line)}.post-editor-wrapper.reply-comment.isFocus[data-v-85e09b4e]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment .toolbar[data-v-85e09b4e]{background:var(--color-editor-toolbar)}.post-editor-wrapper .post-editor[data-v-85e09b4e]{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-85e09b4e]{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-85e09b4e]{display:flex;align-items:center;gap:1rem;font-size:2.6rem}.post-editor-wrapper .toolbar .left svg[data-v-85e09b4e]{cursor:pointer}.post-editor-wrapper .toolbar .left .upload[data-v-85e09b4e]{width:2.6rem;height:2.6rem;overflow:hidden;display:flex;justify-content:center;align-items:center}.post-editor-wrapper .toolbar .left .upload input[data-v-85e09b4e]{width:2.6rem;height:2.6rem;cursor:pointer;position:absolute;opacity:0}.post-editor-wrapper .toolbar span[data-v-85e09b4e]{color:gray;font-size:1.3rem}.post-editor-wrapper .get-cursor[data-v-85e09b4e]{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-85e09b4e]{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 svg[data-v-85e09b4e]{cursor:pointer;position:absolute;right:.8rem;font-size:2.4rem}.post-editor-wrapper .emoticon-pack .list[data-v-85e09b4e]{margin:1rem 0;display:flex;flex-wrap:wrap}.post-editor-wrapper .emoticon-pack img[data-v-85e09b4e]{cursor:pointer;width:calc(100% / 7);padding:.5rem;box-sizing:border-box}.post-editor-wrapper .emoticon-pack span[data-v-85e09b4e]{width:calc(100% / 7);display:inline-block;cursor:pointer;font-size:2.3rem;text-align:center}.v-enter-active[data-v-6f61a860],.v-leave-active[data-v-6f61a860]{transition:opacity .3s ease}.v-enter-from[data-v-6f61a860],.v-leave-to[data-v-6f61a860]{opacity:0}.username[data-v-6f61a860]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-6f61a860]{font-size:1.2rem;font-weight:700;color:#e02a2a}.owner[data-v-6f61a860]{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-6f61a860]{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-6f61a860]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-6f61a860]{display:inline}.my-tag .remove[data-v-6f61a860]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-6f61a860]{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-6f61a860]{margin-left:.5rem;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-6f61a860]: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;--color-top-reply-wrap-bg: #f2f3f5;--color-top-reply-wrap-line: #d2d2d2}html.dark[data-v-6f61a860]{--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;--color-top-reply-wrap-bg: #212f3e;--color-top-reply-wrap-line: #3b536d}html[data-v-6f61a860],body[data-v-6f61a860]{font-size:62.5%}.flex[data-v-6f61a860]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-6f61a860]{justify-content:flex-end}.flex-center[data-v-6f61a860]{justify-content:center}.p1[data-v-6f61a860]{padding:1rem}.p2[data-v-6f61a860]{padding:2rem}.p0[data-v-6f61a860]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-6f61a860]{text-underline-offset:.7ex;text-decoration:underline 1px}a[data-v-6f61a860]{text-decoration:none;cursor:pointer}a[data-v-6f61a860]:hover{text-decoration:underline}.tool[data-v-6f61a860]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.2rem}.tool>svg[data-v-6f61a860]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-6f61a860]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-6f61a860]{cursor:default}.tool.no-hover[data-v-6f61a860]:hover{background:unset!important}.tool.disabled[data-v-6f61a860]{cursor:not-allowed}.tool.disabled[data-v-6f61a860]:hover{background:unset!important}.my-node[data-v-6f61a860]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-6f61a860]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-6f61a860]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-6f61a860]{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%;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-6f61a860]{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-6f61a860]{position:fixed;z-index:1001;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-6f61a860]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-6f61a860]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-6f61a860]{position:relative}.modal .mask[data-v-6f61a860]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-6f61a860]{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-6f61a860]{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-6f61a860]:first-child{border-left:none}.radio-group2 .active[data-v-6f61a860]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-6f61a860]{position:relative;display:inline-flex;justify-content:center}input[data-v-6f61a860]{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-6f61a860]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-6f61a860]:focus{border:1px solid var(--color-active)}.danger[data-v-6f61a860]{color:red!important}.pop-confirm-content[data-v-6f61a860]{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:1003}.pop-confirm-content .text[data-v-6f61a860]{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-6f61a860]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}img[data-v-6f61a860]{max-width:100%}.html-wrapper[data-v-6f61a860]{position:relative}.html-wrapper .mask[data-v-6f61a860]{max-height:90rem;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 80%,transparent)}.html-wrapper .expand[data-v-6f61a860]{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}.top-sub-comment[data-v-d3f8c94b]{width:100%;box-sizing:border-box;margin-top:.8rem;display:flex;position:relative}.top-sub-comment .expand-line[data-v-d3f8c94b]{width:1.6rem;position:relative}.top-sub-comment .expand-line[data-v-d3f8c94b]:after{position:absolute;left:50%;top:2%;content:" ";height:98%;width:0;border-right:1px solid var(--color-top-reply-wrap-line)}.top-sub-comment .right[data-v-d3f8c94b]{flex:1;width:calc(100% - 3rem)}.top-sub-comment .right .w .post-editor-wrapper[data-v-d3f8c94b]{margin-top:1rem}.top-sub-comment[data-v-d3f8c94b] .avatar{display:none!important}.top-sub-comment.top-sub-reply[data-v-d3f8c94b]:first-child{margin-top:0}.top-sub-comment.top-sub-reply>.expand-line[data-v-d3f8c94b]{width:1rem}.top-sub-comment.top-sub-reply>.expand-line[data-v-d3f8c94b]:after{display:none}.comment[data-v-984ba483]{width:100%;box-sizing:border-box;margin-top:.6rem}.comment.isLevelOne[data-v-984ba483]{border-bottom:1px solid var(--color-line);padding:.8rem 1rem;margin-top:0}.comment.ding[data-v-984ba483]{background:rgba(255,255,0,.3)!important}.comment.isSimple .avatar[data-v-984ba483],.comment.isSimple .expand-line[data-v-984ba483]{display:none}.comment.isSimple .simple-wrapper[data-v-984ba483]{padding-left:2.8rem}.comment.isSimple .w[data-v-984ba483]{padding-left:0!important;padding-top:.5rem}.comment .comment-content-w .more[data-v-984ba483]{text-align:center;margin:2rem 0}.comment .comment-content[data-v-984ba483]{display:flex;position:relative}.comment .comment-content .expand-line[data-v-984ba483]{cursor:pointer;margin-top:.6rem;width:2rem;min-width:2rem;position:relative}.comment .comment-content .expand-line[data-v-984ba483]:after{position:absolute;left:50%;content:" ";height:100%;width:0;border-right:1px solid var(--color-line)}.comment .comment-content .expand-line[data-v-984ba483]:hover:after{border-right:2px solid var(--color-active)}.comment .comment-content .right[data-v-984ba483]{flex:1;width:calc(100% - 3rem)}.comment .comment-content .right .w[data-v-984ba483]{padding-left:1rem}.comment .comment-content .right .w .post-editor-wrapper[data-v-984ba483]{margin-top:1rem}.wrong-wrapper[data-v-984ba483]{font-size:1.4rem;margin-bottom:1rem}.wrong-wrapper span[data-v-984ba483]{cursor:pointer}.wrong-wrapper .del-line[data-v-984ba483]{text-decoration:line-through}.wrong-wrapper .wrong-icon[data-v-984ba483]{margin-left:.5rem}.wrong-wrapper .warning[data-v-984ba483]{border-top:1px solid #e1e1e1;border-bottom:1px solid #e1e1e1;padding:1rem 0;margin-top:1rem;font-size:1.2rem;color:red}.reply-count[data-v-984ba483]{padding:.8rem 0 .4rem;border-radius:.2rem;font-size:1.3rem;display:flex;align-items:center;color:gray;gap:1rem;cursor:pointer}.reply-count .gang[data-v-984ba483]{width:2rem;height:0;border-bottom:1px solid #d5d5d5}.reply-count svg[data-v-984ba483]{font-size:1rem}.top-reply-wrap[data-v-984ba483]{background:var(--color-top-reply-wrap-bg);border-radius:.8rem;padding:.6rem;padding-left:0;margin-left:1rem}.toolbar[data-v-30dac564]{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;gap:.5rem}.comment[data-v-4a063111]{width:100%;box-sizing:border-box;display:flex;gap:1rem;padding:1rem;border-bottom:1px solid var(--color-line)}.comment.isSimple .avatar[data-v-4a063111]{display:none}.comment.isSimple .reply_content[data-v-4a063111]{margin-top:.5rem!important}.comment .avatar[data-v-4a063111]{display:flex}.comment .avatar img[data-v-4a063111]{width:3.8rem;height:3.8rem;border-radius:.3rem}.comment .comment-body[data-v-4a063111]{flex:1;display:flex;flex-direction:column}.comment .comment-body .texts[data-v-4a063111]{display:flex;align-items:center}.comment .comment-body .reply_content[data-v-4a063111]{margin-top:1rem;max-width:calc(100% - 5rem)}.comment .isRight[data-v-4a063111]{align-items:flex-end}.comment .isRight .owner[data-v-4a063111],.comment .isRight .mod[data-v-4a063111],.comment .isRight .username[data-v-4a063111]{margin:0 0 0 1rem}.comment .Author-right[data-v-4a063111]{display:flex;flex-direction:column;align-items:center}.comment .Author-right .floor[data-v-4a063111]{margin-left:0}.comment .Author-right .jump[data-v-4a063111]{color:#929596;margin-top:.4rem;font-size:1.4rem}.comment .point[data-v-4a063111]{margin:0 .5rem;font-size:1.6rem;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}.preview-modal{position:fixed;width:100vw;height:100vh;left:0;top:-1000vh;z-index:9999}.preview-modal .close{font-size:2rem;color:#fff;position:absolute;right:2rem;top:2rem;cursor:pointer}.preview-modal .mask{position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,.7);transition:all .3s}.v-enter-active[data-v-d39217d8],.v-leave-active[data-v-d39217d8]{transition:opacity .3s ease}.v-enter-from[data-v-d39217d8],.v-leave-to[data-v-d39217d8]{opacity:0}.username[data-v-d39217d8]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-d39217d8]{font-size:1.2rem;font-weight:700;color:#e02a2a}.owner[data-v-d39217d8]{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-d39217d8]{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-d39217d8]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-d39217d8]{display:inline}.my-tag .remove[data-v-d39217d8]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-d39217d8]{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-d39217d8]{margin-left:.5rem;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-d39217d8]: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;--color-top-reply-wrap-bg: #f2f3f5;--color-top-reply-wrap-line: #d2d2d2}html.dark[data-v-d39217d8]{--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;--color-top-reply-wrap-bg: #212f3e;--color-top-reply-wrap-line: #3b536d}html[data-v-d39217d8],body[data-v-d39217d8]{font-size:62.5%}.flex[data-v-d39217d8]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-d39217d8]{justify-content:flex-end}.flex-center[data-v-d39217d8]{justify-content:center}.p1[data-v-d39217d8]{padding:1rem}.p2[data-v-d39217d8]{padding:2rem}.p0[data-v-d39217d8]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-d39217d8]{text-underline-offset:.7ex;text-decoration:underline 1px}a[data-v-d39217d8]{text-decoration:none;cursor:pointer}a[data-v-d39217d8]:hover{text-decoration:underline}.tool[data-v-d39217d8]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.2rem}.tool>svg[data-v-d39217d8]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-d39217d8]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-d39217d8]{cursor:default}.tool.no-hover[data-v-d39217d8]:hover{background:unset!important}.tool.disabled[data-v-d39217d8]{cursor:not-allowed}.tool.disabled[data-v-d39217d8]:hover{background:unset!important}.my-node[data-v-d39217d8]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-d39217d8]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-d39217d8]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-d39217d8]{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%;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-d39217d8]{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-d39217d8]{position:fixed;z-index:1001;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-d39217d8]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-d39217d8]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-d39217d8]{position:relative}.modal .mask[data-v-d39217d8]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-d39217d8]{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-d39217d8]{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-d39217d8]:first-child{border-left:none}.radio-group2 .active[data-v-d39217d8]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-d39217d8]{position:relative;display:inline-flex;justify-content:center}input[data-v-d39217d8]{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-d39217d8]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-d39217d8]:focus{border:1px solid var(--color-active)}.danger[data-v-d39217d8]{color:red!important}.pop-confirm-content[data-v-d39217d8]{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:1003}.pop-confirm-content .text[data-v-d39217d8]{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-d39217d8]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}img[data-v-d39217d8]{max-width:100%}.Post[data-v-d39217d8]{position:unset!important;background:transparent!important;overflow:unset!important}.Post .main[data-v-d39217d8]{background:transparent!important;padding:unset!important;width:100%!important}.Post .close-btn[data-v-d39217d8],.Post .open-new-tab[data-v-d39217d8]{display:none}.post-detail[data-v-d39217d8]{text-align:start;position:fixed;z-index:1002;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-d39217d8] .subtle{background-color:#ecfdf5e6;border-left:4px solid #a7f3d0}.post-detail.isNight[data-v-d39217d8] .subtle{background-color:#1a3332;border-left:4px solid #047857}.post-detail .main[data-v-d39217d8]{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-d39217d8]{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-d39217d8]{display:inline-block}.post-detail .main .main-wrapper .loading-wrapper[data-v-d39217d8]{height:20rem;display:flex;justify-content:center;align-items:center}.post-detail .main .main-wrapper #no-comments-yet[data-v-d39217d8]{color:#a9a9a9;font-weight:700;text-align:center;width:100%;margin-bottom:2rem;box-sizing:border-box}.post-detail .main .relationReply[data-v-d39217d8]{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-d39217d8]{background:var(--color-second-bg);border-radius:var(--box-border-radius) var(--box-border-radius) 0 0}.post-detail .main .relationReply .comments[data-v-d39217d8]{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-d39217d8]{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-d39217d8]{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-d39217d8],.post-detail .main .call-list .call-item[data-v-d39217d8]:hover,.post-detail .main .call-list .call-item.select[data-v-d39217d8]{background:var(--color-main-bg);text-decoration:none}.post-detail .main .call-list .call-item[data-v-d39217d8]:nth-child(1){border-top:1px solid transparent}@media screen and (max-width: 1280px){.post-detail .main-wrapper[data-v-d39217d8]{width:60vw!important}}.post-detail .v2next-scroll-top[data-v-d39217d8]{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.2rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);color:var(--color-font-3)}.post-detail .v2next-scroll-top svg[data-v-d39217d8]{font-size:2.4rem}.post-detail .refresh[data-v-d39217d8]{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.2rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);color:var(--color-font-3);bottom:23.5rem}.post-detail .refresh svg[data-v-d39217d8]{font-size:2.4rem}.post-detail .scroll-to[data-v-d39217d8]{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.2rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);color:var(--color-font-3);bottom:15rem;display:flex;flex-direction:column}.post-detail .scroll-to svg[data-v-d39217d8]{font-size:2.4rem}.post-detail .scroll-to input[data-v-d39217d8]{height:2.6rem;width:3.6rem;font-size:1.4rem;text-align:center;color:gray}.post-detail .msg[data-v-d39217d8]{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.2rem;transform:translate(6rem);font-size:2rem;background:var(--color-sp-btn-bg);color:var(--color-font-3);bottom:5rem}.post-detail .msg svg[data-v-d39217d8]{font-size:2.4rem}.post-detail .close-btn[data-v-d39217d8]{color:var(--color-font-3);cursor:pointer;position:fixed;top:3rem;transform:translate(4rem);font-size:2.4rem}.post-detail .top-reply[data-v-d39217d8]{color:var(--color-font-3);cursor:pointer;font-size:2rem;display:flex}.post-detail .open-new-tab[data-v-d39217d8]{color:var(--color-font-3);cursor:pointer;position:fixed;top:3rem;transform:translate(4rem);font-size:2.4rem;top:8rem}.specific-area[data-v-d39217d8]{--color-line: #6a6868;--color-floor: rgba(71, 71, 71, .48);--color-top-reply-wrap-bg: rgba(71, 71, 71, .48);--color-sp-btn-bg: rgba(71, 71, 71, .48);--color-editor-toolbar: #303e64;--color-font-pure: white;--color-main-bg: #545454;--box-background-color: rgba(0, 0, 0, .5);--box-background-hover-color: rgba(0, 0, 0, .5)}.specific-area .my-box[data-v-d39217d8]{color:#fff;border-bottom:2px solid rgba(0,0,0,.4);-webkit-backdrop-filter:blur(15px);backdrop-filter:blur(15px)}.base64_tooltip[data-v-06429e70]{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-06429e70]{margin-left:1rem;font-size:3rem;color:var(--color-gray)}.base64_tooltip[data-v-06429e70] .base-button{margin-left:1rem;margin-top:1rem}.msg[data-v-8bf692ea]{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-8bf692ea]{background:var(--color-active)}.msg.warning .left[data-v-8bf692ea]{background:#c8c002}.msg.error .left[data-v-8bf692ea]{background:red}.msg .left[data-v-8bf692ea]{border-radius:var(--box-border-radius) 0 0 var(--box-border-radius);display:flex;align-items:center;background:var(--color-active);color:#fff;width:3.6rem;font-size:2.4rem;justify-content:center}.msg .left svg[data-v-8bf692ea]{cursor:pointer}.msg .right[data-v-8bf692ea]{flex:1;padding:1rem 2rem;display:flex;justify-content:space-between;align-items:center}.tag-modal[data-v-0f1f99f7]{z-index:1003}.tag-modal .wrapper[data-v-0f1f99f7]{z-index:9;background:var(--color-main-bg);color:var(--color-font-8);border-radius:1rem;font-size:1.4rem;padding:2rem 4rem;width:25rem}.tag-modal .wrapper .title[data-v-0f1f99f7]{font-weight:700}.tag-modal .wrapper .btns[data-v-0f1f99f7]{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}.NotificationModal .modal-root[data-v-77aa374e]{z-index:9;background:var(--color-second-bg);color:var(--color-font-8);border-radius:1rem;font-size:1.4rem;width:50vw;height:80vh;display:flex;flex-direction:column;padding:1.4rem;gap:1rem}.NotificationModal .modal-root .modal-header[data-v-77aa374e]{display:flex;justify-content:space-between}.NotificationModal .modal-root .modal-header .title[data-v-77aa374e]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.NotificationModal .modal-root .modal-header i[data-v-77aa374e]{cursor:pointer;font-size:2.2rem}.NotificationModal .modal-root .modal-body[data-v-77aa374e]{padding-top:0;flex:1;gap:1rem;display:flex;flex-direction:column;overflow:hidden}.NotificationModal .modal-root .modal-body .filter[data-v-77aa374e]{display:flex;gap:1rem}.NotificationModal .modal-root .modal-body .filter div[data-v-77aa374e]{border-radius:.4rem;padding:.4rem 1rem;background:gainsboro;cursor:pointer}.NotificationModal .modal-root .modal-body .filter div.active[data-v-77aa374e]{background:#445;color:#fff}.NotificationModal .modal-root .modal-body .list-wrap[data-v-77aa374e]{flex:1;position:relative;overflow:hidden}.NotificationModal .modal-root .modal-body .list-wrap .loading-wrap[data-v-77aa374e]{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;background:rgba(255,255,255,.7)}.NotificationModal .modal-root .modal-body .list-wrap .notify-wrap[data-v-77aa374e]{overflow:auto;height:100%}.NotificationModal .modal-root .modal-body .list-wrap #notifications[data-v-77aa374e] .cell{display:none;padding:1.2rem 0}.NotificationModal .modal-root .modal-body .list-wrap #notifications[data-v-77aa374e] .cell a.node{padding:.6rem 1rem;border-radius:.4rem}.NotificationModal .modal-root .modal-body .list-wrap #notifications[data-v-77aa374e] .cell .payload{margin-top:.4rem;font-size:1.7rem}.NotificationModal .modal-root .modal-body #notifications.all[data-v-77aa374e] .cell,.NotificationModal .modal-root .modal-body #notifications.reply[data-v-77aa374e] .reply,.NotificationModal .modal-root .modal-body #notifications.star[data-v-77aa374e] .star,.NotificationModal .modal-root .modal-body #notifications.collect[data-v-77aa374e] .collect{display:block}.NotificationModal .modal-root .modal-body .footer[data-v-77aa374e]{width:100%;display:flex;align-items:center;gap:2rem}.NotificationModal .modal-root .modal-body .footer .pages[data-v-77aa374e]{flex:1}.NotificationModal .modal-root .modal-body .footer .total[data-v-77aa374e]{font-weight:700}.NotificationModal .modal-root .modal-body .footer .total span[data-v-77aa374e]{color:#d3d3d3;font-weight:400;margin-right:.4rem}.NotificationModal .modal-root .modal-body[data-v-77aa374e] .super.button{padding:0;background:unset;height:26px;width:37px}.NotificationModal .modal-root .modal-body[data-v-77aa374e] .super.button a{display:block}.NotificationModal .modal-root .modal-body[data-v-77aa374e] .super.button a:hover{text-decoration:none}.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-size:1.2rem;font-weight:700;color:#e02a2a}.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:.5rem;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;--color-top-reply-wrap-bg: #f2f3f5;--color-top-reply-wrap-line: #d2d2d2}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;--color-top-reply-wrap-bg: #212f3e;--color-top-reply-wrap-line: #3b536d}html,body{font-size:62.5%}.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:.7ex;text-decoration:underline 1px}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:.2rem}.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%;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:1001;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}.pop-confirm-content{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:1003}.pop-confirm-content .text{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}img{max-width:100%}.target-user-tags[data-v-a73f564c]{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-a73f564c]{display:inline-block}.loaded[data-v-a73f564c]{font-size:1.4rem;display:flex;align-items:center;gap:1rem;color:var(--color-font-pure)}.calender[data-v-a73f564c]{padding:10px;font-size:14px;color:var(--link-color)}.calender .month[data-v-a73f564c]{height:30px;display:flex;justify-content:space-between;align-items:center}.calender .month .ca-title[data-v-a73f564c]{flex:1;display:flex;justify-content:flex-end;align-items:center;gap:10px}.calender .month i[data-v-a73f564c]{height:100%;width:30px;cursor:pointer;color:#a9a9a9}.calender .calender-header[data-v-a73f564c]{display:flex;height:30px;align-items:center}.calender .calender-header div[data-v-a73f564c]{flex:1}.calender .days[data-v-a73f564c]{display:grid;grid-template-columns:repeat(7,1fr)}.calender .days .day[data-v-a73f564c]{height:30px}.calender .days .day a[data-v-a73f564c]{display:inline-flex;height:100%;width:100%;justify-content:center;align-items:center}.calender .days .active[data-v-a73f564c]{background:#40a9ff;border-radius:4px}.calender .days .active a[data-v-a73f564c]{color:#fff!important} ');
  8847.  
  8848. run();
  8849. let vueApp = vue.createApp(App);
  8850. vueApp.config.unwrapInjectedRef = true;
  8851. vueApp.mount($section);
  8852. }
  8853.  
  8854. })(Vue, dayjs);