V2Next

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

当前为 2024-02-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name V2Next
  3. // @namespace http://tampermonkey.net/
  4. // @version 8.1.1
  5. // @author zyronon
  6. // @description V2Next - 一个好用的V2EX脚本! 已适配移动端
  7. // @license GPL License
  8. // @icon https://v2next.netlify.app/favicon.ico
  9. // @homepage https://github.com/zyronon/web-scripts
  10. // @homepageURL https://github.com/zyronon/web-scripts
  11. // @supportURL https://update.greasyfork.org/scripts/458024/V2Next.user.js
  12. // @match https://v2ex.com/
  13. // @match https://v2ex.com/?tab=*
  14. // @match https://v2ex.com/t/*
  15. // @match https://v2ex.com/recent*
  16. // @match https://v2ex.com/go/*
  17. // @match https://v2ex.com/member/*
  18. // @match https://v2ex.com/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/vue@3.4.14/dist/vue.global.prod.js
  27. // @grant GM_addStyle
  28. // @grant GM_notification
  29. // @grant GM_openInTab
  30. // @grant GM_registerMenuCommand
  31. // ==/UserScript==
  32.  
  33.  
  34. (function (vue) {
  35. 'use strict';
  36.  
  37. var PageType = /* @__PURE__ */ ((PageType2) => {
  38. PageType2["Home"] = "Home";
  39. PageType2["Node"] = "Node";
  40. PageType2["Post"] = "Post";
  41. PageType2["Member"] = "Member";
  42. PageType2["Changes"] = "Changes";
  43. return PageType2;
  44. })(PageType || {});
  45. var CommentDisplayType = /* @__PURE__ */ ((CommentDisplayType2) => {
  46. CommentDisplayType2[CommentDisplayType2["FloorInFloor"] = 0] = "FloorInFloor";
  47. CommentDisplayType2[CommentDisplayType2["FloorInFloorNoCallUser"] = 4] = "FloorInFloorNoCallUser";
  48. CommentDisplayType2[CommentDisplayType2["FloorInFloorNested"] = 5] = "FloorInFloorNested";
  49. CommentDisplayType2[CommentDisplayType2["Like"] = 1] = "Like";
  50. CommentDisplayType2[CommentDisplayType2["V2exOrigin"] = 2] = "V2exOrigin";
  51. CommentDisplayType2[CommentDisplayType2["OnlyOp"] = 3] = "OnlyOp";
  52. CommentDisplayType2[CommentDisplayType2["New"] = 6] = "New";
  53. return CommentDisplayType2;
  54. })(CommentDisplayType || {});
  55. const MAX_REPLY_LIMIT = 400;
  56. const _sfc_main$l = {
  57. name: "Tooltip",
  58. props: {
  59. title: {
  60. type: String,
  61. default() {
  62. return "";
  63. }
  64. },
  65. disabled: {
  66. type: Boolean,
  67. default() {
  68. return false;
  69. }
  70. }
  71. },
  72. data() {
  73. return {
  74. show: false
  75. };
  76. },
  77. methods: {
  78. showPop(e2) {
  79. if (this.disabled)
  80. return;
  81. if (!this.title)
  82. return;
  83. e2.stopPropagation();
  84. let rect = e2.target.getBoundingClientRect();
  85. this.show = true;
  86. vue.nextTick(() => {
  87. var _a, _b;
  88. let tip = (_b = (_a = this.$refs) == null ? void 0 : _a.tip) == null ? void 0 : _b.getBoundingClientRect();
  89. if (!tip)
  90. return;
  91. if (rect.top < 50) {
  92. this.$refs.tip.style.top = rect.top + rect.height + 10 + "px";
  93. } else {
  94. this.$refs.tip.style.top = rect.top - tip.height - 10 + "px";
  95. }
  96. let tipWidth = tip.width;
  97. let rectWidth = rect.width;
  98. this.$refs.tip.style.left = rect.left - (tipWidth - rectWidth) / 2 + "px";
  99. });
  100. }
  101. },
  102. render() {
  103. let Vnode = this.$slots.default()[0];
  104. return vue.createVNode(vue.Fragment, null, [this.show && this.title && vue.createVNode(vue.Teleport, {
  105. "to": "body"
  106. }, {
  107. default: () => [vue.createVNode(vue.Transition, {
  108. "name": "fade"
  109. }, {
  110. default: () => [vue.createVNode("div", {
  111. "ref": "tip",
  112. "className": "tip"
  113. }, [this.title])]
  114. })]
  115. }), vue.createVNode(Vnode, {
  116. "onClick": () => this.show = false,
  117. "onmouseenter": (e2) => this.showPop(e2),
  118. "onmouseleave": () => this.show = false
  119. }, null)]);
  120. }
  121. };
  122. const _export_sfc = (sfc, props) => {
  123. const target = sfc.__vccOpts || sfc;
  124. for (const [key, val] of props) {
  125. target[key] = val;
  126. }
  127. return target;
  128. };
  129. const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-ee672411"]]);
  130. const _sfc_main$k = /* @__PURE__ */ vue.defineComponent({
  131. __name: "BaseSwitch",
  132. props: {
  133. modelValue: { type: Boolean }
  134. },
  135. emits: ["update:modelValue"],
  136. setup(__props, { emit: __emit }) {
  137. return (_ctx, _cache) => {
  138. return vue.openBlock(), vue.createElementBlock("div", {
  139. class: vue.normalizeClass(["switch", { active: _ctx.modelValue }]),
  140. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", !_ctx.modelValue))
  141. }, null, 2);
  142. };
  143. }
  144. });
  145. const BaseSwitch = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-e7c0fbef"]]);
  146. var _GM_notification = /* @__PURE__ */ (() => typeof GM_notification != "undefined" ? GM_notification : void 0)();
  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. //获取所有回复
  151. getAllReply(repliesMap = []) {
  152. return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
  153. pre = pre.concat(i.replyList);
  154. return pre;
  155. }, []);
  156. },
  157. //查找子回复
  158. findChildren(item, endList, all) {
  159. var _a;
  160. const fn = (child, endList2, parent) => {
  161. child.level = parent.level + 1;
  162. let rIndex = all.findIndex((v) => v.floor === child.floor);
  163. if (rIndex > -1) {
  164. all[rIndex].isUse = true;
  165. }
  166. parent.children.push(this.findChildren(child, endList2, all));
  167. };
  168. item.children = [];
  169. let floorReplyList = [];
  170. for (let i = 0; i < endList.length; i++) {
  171. let currentItem = endList[i];
  172. if (currentItem.isUse)
  173. continue;
  174. if (currentItem.replyFloor === item.floor) {
  175. if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
  176. currentItem.isUse = true;
  177. floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
  178. } else {
  179. currentItem.isWrong = true;
  180. }
  181. }
  182. }
  183. floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
  184. fn(currentItem, endList2, item);
  185. });
  186. let nextMeIndex = endList.findIndex((v) => {
  187. var _a2;
  188. return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
  189. });
  190. let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
  191. for (let i = 0; i < findList.length; i++) {
  192. let currentItem = findList[i];
  193. if (currentItem.isUse)
  194. continue;
  195. if (currentItem.replyUsers.length === 1) {
  196. if (currentItem.replyFloor !== -1) {
  197. if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
  198. continue;
  199. }
  200. }
  201. let endList2 = endList.slice(i + 1);
  202. if (currentItem.username === item.username) {
  203. if (currentItem.replyUsers[0] === item.username) {
  204. fn(currentItem, endList2, item);
  205. }
  206. break;
  207. } else {
  208. if (currentItem.replyUsers[0] === item.username) {
  209. fn(currentItem, endList2, item);
  210. }
  211. }
  212. } else {
  213. if (currentItem.username === item.username)
  214. break;
  215. }
  216. }
  217. item.children = item.children.sort((a, b) => a.floor - b.floor);
  218. return item;
  219. },
  220. //生成嵌套回复
  221. createNestedList(allList = []) {
  222. if (!allList.length)
  223. return [];
  224. let list = window.clone(allList);
  225. let nestedList = [];
  226. list.map((item, index) => {
  227. let startList = list.slice(0, index);
  228. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  229. let endList = list.slice(index + 1);
  230. if (index === 0) {
  231. nestedList.push(this.findChildren(item, endList, list));
  232. } else {
  233. if (!item.isUse) {
  234. let isOneLevelReply = false;
  235. if (item.replyUsers.length) {
  236. if (item.replyUsers.length > 1) {
  237. isOneLevelReply = true;
  238. } else {
  239. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  240. }
  241. } else {
  242. isOneLevelReply = true;
  243. }
  244. if (isOneLevelReply) {
  245. item.level = 0;
  246. nestedList.push(this.findChildren(item, endList, list));
  247. }
  248. }
  249. }
  250. });
  251. return nestedList;
  252. },
  253. //生成嵌套冗余回复
  254. createNestedRedundantList(allList = []) {
  255. if (!allList.length)
  256. return [];
  257. let list = window.clone(allList);
  258. let nestedList = [];
  259. list.map((item, index) => {
  260. let startList = list.slice(0, index);
  261. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  262. let endList = list.slice(index + 1);
  263. if (index === 0) {
  264. nestedList.push(this.findChildren(item, endList, list));
  265. } else {
  266. if (!item.isUse) {
  267. let isOneLevelReply = false;
  268. if (item.replyUsers.length) {
  269. if (item.replyUsers.length > 1) {
  270. isOneLevelReply = true;
  271. } else {
  272. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  273. }
  274. } else {
  275. isOneLevelReply = true;
  276. }
  277. if (isOneLevelReply) {
  278. item.level = 0;
  279. nestedList.push(this.findChildren(item, endList, list));
  280. }
  281. } else {
  282. let newItem = window.clone(item);
  283. newItem.children = [];
  284. newItem.level = 0;
  285. newItem.isDup = true;
  286. nestedList.push(newItem);
  287. }
  288. }
  289. });
  290. return nestedList;
  291. },
  292. //解析A标签
  293. parseA(a) {
  294. let href = a.href;
  295. let id;
  296. if (href.includes("/t/")) {
  297. id = a.pathname.substring("/t/".length);
  298. }
  299. return { href, id, title: a.innerText };
  300. },
  301. //图片链接转Img标签
  302. checkPhotoLink2Img(str) {
  303. if (!str)
  304. return;
  305. try {
  306. let imgWebs = [
  307. /<a((?!<a).)*href="https?:\/\/((?!<a).)*imgur.com((?!<a).)*>(((?!<a).)*)<\/a>/g,
  308. /<a((?!<a).)*href="https?:\/\/((?!<a).)*\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG) ((?!<a).)*>(((?!<a).)*)<\/a>/g
  309. ];
  310. imgWebs.map((v, i) => {
  311. let has = str.matchAll(v);
  312. let res2 = [...has];
  313. res2.map((r2) => {
  314. let p = i === 0 ? r2[4] : r2[5];
  315. if (p) {
  316. let link = p.toLowerCase();
  317. let src = p;
  318. if (link.includes(".png") || link.includes(".jpg") || link.includes(".jpeg") || link.includes(".gif")) {
  319. } else {
  320. src = p + ".png";
  321. }
  322. str = str.replace(r2[0], `<img src="${src}" data-originUrl="${p}" data-notice="此img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`);
  323. }
  324. });
  325. });
  326. } catch (e2) {
  327. console.log("正则解析html里面的a标签的图片链接出错了");
  328. }
  329. return str;
  330. },
  331. //检测帖子回复长度
  332. async checkPostReplies(id, needOpen = true) {
  333. return new Promise(async (resolve) => {
  334. let res = await functions.getPostDetailByApi(id);
  335. if ((res == null ? void 0 : res.replies) > MAX_REPLY_LIMIT) {
  336. if (needOpen) {
  337. functions.openNewTab(`https://${location.origin}/t/${id}?p=1&script=1`);
  338. }
  339. return resolve(true);
  340. }
  341. resolve(false);
  342. });
  343. },
  344. async sleep(time) {
  345. return new Promise((resolve) => {
  346. setTimeout(resolve, time);
  347. });
  348. },
  349. //打开新标签页
  350. openNewTab(href, active = false) {
  351. _GM_openInTab(href, { active });
  352. },
  353. async cbChecker(val, count = 0) {
  354. if (window.cb) {
  355. window.cb(val);
  356. } else {
  357. while (!window.cb && count < 30) {
  358. await functions.sleep(500);
  359. count++;
  360. }
  361. window.cb && window.cb(val);
  362. }
  363. },
  364. //初始化脚本菜单
  365. initMonkeyMenu() {
  366. try {
  367. _GM_registerMenuCommand("脚本设置", () => {
  368. functions.cbChecker({ type: "openSetting" });
  369. });
  370. _GM_registerMenuCommand("仓库地址", () => {
  371. functions.openNewTab(window.const.git);
  372. });
  373. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  374. } catch (e2) {
  375. console.error("无法使用Tampermonkey");
  376. }
  377. },
  378. clone(val) {
  379. return JSON.parse(JSON.stringify(val));
  380. },
  381. feedback() {
  382. functions.openNewTab(DefaultVal.issue);
  383. },
  384. //检测页面类型
  385. checkPageType(a) {
  386. let l = a || window.location;
  387. let data = { pageType: null, pageData: { id: "", pageNo: null } };
  388. if (l.pathname === "/") {
  389. data.pageType = PageType.Home;
  390. } else if (l.pathname === "/changes") {
  391. data.pageType = PageType.Changes;
  392. } else if (l.pathname === "/recent") {
  393. data.pageType = PageType.Changes;
  394. } else if (l.href.match(/.com\/?tab=/)) {
  395. data.pageType = PageType.Home;
  396. } else if (l.href.match(/.com\/go\//)) {
  397. if (!l.href.includes("/links")) {
  398. data.pageType = PageType.Node;
  399. }
  400. } else if (l.href.match(/.com\/member/)) {
  401. data.pageType = PageType.Member;
  402. } else {
  403. let r2 = l.href.match(/.com\/t\/([\d]+)/);
  404. if (r2 && !l.pathname.includes("review") && !l.pathname.includes("info")) {
  405. data.pageType = PageType.Post;
  406. data.pageData.id = r2[1];
  407. if (l.search) {
  408. let pr = l.href.match(/\?p=([\d]+)/);
  409. if (pr)
  410. data.pageData.pageNo = Number(pr[1]);
  411. }
  412. }
  413. }
  414. return data;
  415. },
  416. //通过api获取主题详情
  417. getPostDetailByApi(id) {
  418. return new Promise((resolve) => {
  419. fetch(`${location.origin}/api/topics/show.json?id=${id}`).then(async (r2) => {
  420. if (r2.status === 200) {
  421. let res = await r2.json();
  422. if (res) {
  423. let d2 = res[0];
  424. resolve(d2);
  425. }
  426. }
  427. });
  428. });
  429. },
  430. appendPostContent(res, el) {
  431. let a = document.createElement("a");
  432. a.href = res.href;
  433. a.classList.add("post-content");
  434. let div = document.createElement("div");
  435. div.innerHTML = res.content_rendered;
  436. a.append(div);
  437. el.append(a);
  438. const checkHeight2 = () => {
  439. var _a;
  440. if (div.clientHeight < 300) {
  441. a.classList.add("show-all");
  442. } else {
  443. let showMore = document.createElement("div");
  444. showMore.classList.add("show-more");
  445. showMore.innerHTML = "显示更多/收起";
  446. showMore.onclick = function(e2) {
  447. e2.stopPropagation();
  448. a.classList.toggle("show-all");
  449. };
  450. (_a = a.parentNode) == null ? void 0 : _a.append(showMore);
  451. }
  452. };
  453. checkHeight2();
  454. },
  455. //从本地读取配置
  456. initConfig() {
  457. return new Promise((resolve) => {
  458. let configStr = localStorage.getItem("v2ex-config");
  459. if (configStr) {
  460. let configObj = JSON.parse(configStr);
  461. configObj = configObj[window.user.username ?? "default"];
  462. if (configObj) {
  463. window.config = Object.assign(window.config, configObj);
  464. }
  465. }
  466. resolve(window.config);
  467. });
  468. }
  469. };
  470. const DefaultPost = {
  471. allReplyUsers: [],
  472. content_rendered: "",
  473. createDate: "",
  474. createDateAgo: "",
  475. lastReplyDate: "",
  476. fr: "",
  477. replyList: [],
  478. nestedReplies: [],
  479. nestedRedundReplies: [],
  480. username: "",
  481. url: "",
  482. href: "",
  483. member: {},
  484. node: {
  485. title: "",
  486. url: ""
  487. },
  488. headerTemplate: "",
  489. title: "",
  490. id: "",
  491. type: "post",
  492. once: "",
  493. replyCount: 0,
  494. clickCount: 0,
  495. thankCount: 0,
  496. collectCount: 0,
  497. lastReadFloor: 0,
  498. isFavorite: false,
  499. isIgnore: false,
  500. isThanked: false,
  501. isReport: false,
  502. inList: false
  503. };
  504. const getDefaultPost = (val = {}) => {
  505. return Object.assign(functions.clone(DefaultPost), val);
  506. };
  507. const DefaultUser = {
  508. tagPrefix: "--用户标签--",
  509. tags: {},
  510. tagsId: "",
  511. username: "",
  512. avatar: "",
  513. readPrefix: "--已读楼层--",
  514. readNoteItemId: "",
  515. readList: {},
  516. imgurPrefix: "--imgur图片删除hash--",
  517. imgurList: {},
  518. imgurNoteId: ""
  519. };
  520. const DefaultConfig = {
  521. showToolbar: true,
  522. autoOpenDetail: true,
  523. openTag: false,
  524. //给用户打标签
  525. clickPostItemOpenDetail: true,
  526. closePostDetailBySpace: true,
  527. //点击空白处关闭详情
  528. contentAutoCollapse: true,
  529. //正文超长自动折叠
  530. viewType: "table",
  531. commentDisplayType: CommentDisplayType.FloorInFloorNoCallUser,
  532. newTabOpen: false,
  533. //新标签打开
  534. newTabOpenActive: false,
  535. base64: true,
  536. //base功能
  537. sov2ex: false,
  538. postWidth: "",
  539. showTopReply: true,
  540. topReplyLoveMinCount: 3,
  541. topReplyCount: 3,
  542. autoJumpLastReadFloor: false,
  543. rememberLastReadFloor: false,
  544. autoSignin: true,
  545. customBgColor: "",
  546. version: 1,
  547. collectBrowserNotice: false,
  548. fontSizeType: "normal"
  549. };
  550. const DefaultVal = {
  551. pageType: void 0,
  552. pageData: { pageNo: 1 },
  553. targetUserName: "",
  554. currentVersion: 1,
  555. isNight: false,
  556. cb: null,
  557. stopMe: null,
  558. postList: [],
  559. git: "https://github.com/zyronon/web-scripts",
  560. shortGit: "zyronon/web-scripts",
  561. issue: "https://github.com/zyronon/web-scripts/issues",
  562. pcLog: "https://greasyfork.org/zh-CN/scripts/458024/versions",
  563. pcScript: "https://greasyfork.org/zh-CN/scripts/458024",
  564. mobileScript: "https://greasyfork.org/zh-CN/scripts/485356",
  565. homeUrl: "https://v2next.netlify.app/"
  566. };
  567. const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
  568. const stringToIcon = (value, validate, allowSimpleName, provider = "") => {
  569. const colonSeparated = value.split(":");
  570. if (value.slice(0, 1) === "@") {
  571. if (colonSeparated.length < 2 || colonSeparated.length > 3) {
  572. return null;
  573. }
  574. provider = colonSeparated.shift().slice(1);
  575. }
  576. if (colonSeparated.length > 3 || !colonSeparated.length) {
  577. return null;
  578. }
  579. if (colonSeparated.length > 1) {
  580. const name2 = colonSeparated.pop();
  581. const prefix = colonSeparated.pop();
  582. const result = {
  583. // Allow provider without '@': "provider:prefix:name"
  584. provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
  585. prefix,
  586. name: name2
  587. };
  588. return validate && !validateIconName(result) ? null : result;
  589. }
  590. const name = colonSeparated[0];
  591. const dashSeparated = name.split("-");
  592. if (dashSeparated.length > 1) {
  593. const result = {
  594. provider,
  595. prefix: dashSeparated.shift(),
  596. name: dashSeparated.join("-")
  597. };
  598. return validate && !validateIconName(result) ? null : result;
  599. }
  600. if (allowSimpleName && provider === "") {
  601. const result = {
  602. provider,
  603. prefix: "",
  604. name
  605. };
  606. return validate && !validateIconName(result, allowSimpleName) ? null : result;
  607. }
  608. return null;
  609. };
  610. const validateIconName = (icon, allowSimpleName) => {
  611. if (!icon) {
  612. return false;
  613. }
  614. return !!((icon.provider === "" || icon.provider.match(matchIconName)) && (allowSimpleName && icon.prefix === "" || icon.prefix.match(matchIconName)) && icon.name.match(matchIconName));
  615. };
  616. const defaultIconDimensions = Object.freeze(
  617. {
  618. left: 0,
  619. top: 0,
  620. width: 16,
  621. height: 16
  622. }
  623. );
  624. const defaultIconTransformations = Object.freeze({
  625. rotate: 0,
  626. vFlip: false,
  627. hFlip: false
  628. });
  629. const defaultIconProps = Object.freeze({
  630. ...defaultIconDimensions,
  631. ...defaultIconTransformations
  632. });
  633. const defaultExtendedIconProps = Object.freeze({
  634. ...defaultIconProps,
  635. body: "",
  636. hidden: false
  637. });
  638. function mergeIconTransformations(obj1, obj2) {
  639. const result = {};
  640. if (!obj1.hFlip !== !obj2.hFlip) {
  641. result.hFlip = true;
  642. }
  643. if (!obj1.vFlip !== !obj2.vFlip) {
  644. result.vFlip = true;
  645. }
  646. const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
  647. if (rotate) {
  648. result.rotate = rotate;
  649. }
  650. return result;
  651. }
  652. function mergeIconData(parent, child) {
  653. const result = mergeIconTransformations(parent, child);
  654. for (const key in defaultExtendedIconProps) {
  655. if (key in defaultIconTransformations) {
  656. if (key in parent && !(key in result)) {
  657. result[key] = defaultIconTransformations[key];
  658. }
  659. } else if (key in child) {
  660. result[key] = child[key];
  661. } else if (key in parent) {
  662. result[key] = parent[key];
  663. }
  664. }
  665. return result;
  666. }
  667. function getIconsTree(data, names) {
  668. const icons = data.icons;
  669. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  670. const resolved = /* @__PURE__ */ Object.create(null);
  671. function resolve(name) {
  672. if (icons[name]) {
  673. return resolved[name] = [];
  674. }
  675. if (!(name in resolved)) {
  676. resolved[name] = null;
  677. const parent = aliases[name] && aliases[name].parent;
  678. const value = parent && resolve(parent);
  679. if (value) {
  680. resolved[name] = [parent].concat(value);
  681. }
  682. }
  683. return resolved[name];
  684. }
  685. (names || Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);
  686. return resolved;
  687. }
  688. function internalGetIconData(data, name, tree) {
  689. const icons = data.icons;
  690. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  691. let currentProps = {};
  692. function parse(name2) {
  693. currentProps = mergeIconData(
  694. icons[name2] || aliases[name2],
  695. currentProps
  696. );
  697. }
  698. parse(name);
  699. tree.forEach(parse);
  700. return mergeIconData(data, currentProps);
  701. }
  702. function parseIconSet(data, callback) {
  703. const names = [];
  704. if (typeof data !== "object" || typeof data.icons !== "object") {
  705. return names;
  706. }
  707. if (data.not_found instanceof Array) {
  708. data.not_found.forEach((name) => {
  709. callback(name, null);
  710. names.push(name);
  711. });
  712. }
  713. const tree = getIconsTree(data);
  714. for (const name in tree) {
  715. const item = tree[name];
  716. if (item) {
  717. callback(name, internalGetIconData(data, name, item));
  718. names.push(name);
  719. }
  720. }
  721. return names;
  722. }
  723. const optionalPropertyDefaults = {
  724. provider: "",
  725. aliases: {},
  726. not_found: {},
  727. ...defaultIconDimensions
  728. };
  729. function checkOptionalProps(item, defaults) {
  730. for (const prop in defaults) {
  731. if (prop in item && typeof item[prop] !== typeof defaults[prop]) {
  732. return false;
  733. }
  734. }
  735. return true;
  736. }
  737. function quicklyValidateIconSet(obj) {
  738. if (typeof obj !== "object" || obj === null) {
  739. return null;
  740. }
  741. const data = obj;
  742. if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") {
  743. return null;
  744. }
  745. if (!checkOptionalProps(obj, optionalPropertyDefaults)) {
  746. return null;
  747. }
  748. const icons = data.icons;
  749. for (const name in icons) {
  750. const icon = icons[name];
  751. if (!name.match(matchIconName) || typeof icon.body !== "string" || !checkOptionalProps(
  752. icon,
  753. defaultExtendedIconProps
  754. )) {
  755. return null;
  756. }
  757. }
  758. const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
  759. for (const name in aliases) {
  760. const icon = aliases[name];
  761. const parent = icon.parent;
  762. if (!name.match(matchIconName) || typeof parent !== "string" || !icons[parent] && !aliases[parent] || !checkOptionalProps(
  763. icon,
  764. defaultExtendedIconProps
  765. )) {
  766. return null;
  767. }
  768. }
  769. return data;
  770. }
  771. const dataStorage = /* @__PURE__ */ Object.create(null);
  772. function newStorage(provider, prefix) {
  773. return {
  774. provider,
  775. prefix,
  776. icons: /* @__PURE__ */ Object.create(null),
  777. missing: /* @__PURE__ */ new Set()
  778. };
  779. }
  780. function getStorage(provider, prefix) {
  781. const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));
  782. return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));
  783. }
  784. function addIconSet(storage2, data) {
  785. if (!quicklyValidateIconSet(data)) {
  786. return [];
  787. }
  788. return parseIconSet(data, (name, icon) => {
  789. if (icon) {
  790. storage2.icons[name] = icon;
  791. } else {
  792. storage2.missing.add(name);
  793. }
  794. });
  795. }
  796. function addIconToStorage(storage2, name, icon) {
  797. try {
  798. if (typeof icon.body === "string") {
  799. storage2.icons[name] = { ...icon };
  800. return true;
  801. }
  802. } catch (err) {
  803. }
  804. return false;
  805. }
  806. let simpleNames = false;
  807. function allowSimpleNames(allow) {
  808. if (typeof allow === "boolean") {
  809. simpleNames = allow;
  810. }
  811. return simpleNames;
  812. }
  813. function getIconData(name) {
  814. const icon = typeof name === "string" ? stringToIcon(name, true, simpleNames) : name;
  815. if (icon) {
  816. const storage2 = getStorage(icon.provider, icon.prefix);
  817. const iconName = icon.name;
  818. return storage2.icons[iconName] || (storage2.missing.has(iconName) ? null : void 0);
  819. }
  820. }
  821. function addIcon(name, data) {
  822. const icon = stringToIcon(name, true, simpleNames);
  823. if (!icon) {
  824. return false;
  825. }
  826. const storage2 = getStorage(icon.provider, icon.prefix);
  827. return addIconToStorage(storage2, icon.name, data);
  828. }
  829. function addCollection(data, provider) {
  830. if (typeof data !== "object") {
  831. return false;
  832. }
  833. if (typeof provider !== "string") {
  834. provider = data.provider || "";
  835. }
  836. if (simpleNames && !provider && !data.prefix) {
  837. let added = false;
  838. if (quicklyValidateIconSet(data)) {
  839. data.prefix = "";
  840. parseIconSet(data, (name, icon) => {
  841. if (icon && addIcon(name, icon)) {
  842. added = true;
  843. }
  844. });
  845. }
  846. return added;
  847. }
  848. const prefix = data.prefix;
  849. if (!validateIconName({
  850. provider,
  851. prefix,
  852. name: "a"
  853. })) {
  854. return false;
  855. }
  856. const storage2 = getStorage(provider, prefix);
  857. return !!addIconSet(storage2, data);
  858. }
  859. const defaultIconSizeCustomisations = Object.freeze({
  860. width: null,
  861. height: null
  862. });
  863. const defaultIconCustomisations = Object.freeze({
  864. // Dimensions
  865. ...defaultIconSizeCustomisations,
  866. // Transformations
  867. ...defaultIconTransformations
  868. });
  869. const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
  870. const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
  871. function calculateSize(size, ratio, precision) {
  872. if (ratio === 1) {
  873. return size;
  874. }
  875. precision = precision || 100;
  876. if (typeof size === "number") {
  877. return Math.ceil(size * ratio * precision) / precision;
  878. }
  879. if (typeof size !== "string") {
  880. return size;
  881. }
  882. const oldParts = size.split(unitsSplit);
  883. if (oldParts === null || !oldParts.length) {
  884. return size;
  885. }
  886. const newParts = [];
  887. let code = oldParts.shift();
  888. let isNumber = unitsTest.test(code);
  889. while (true) {
  890. if (isNumber) {
  891. const num = parseFloat(code);
  892. if (isNaN(num)) {
  893. newParts.push(code);
  894. } else {
  895. newParts.push(Math.ceil(num * ratio * precision) / precision);
  896. }
  897. } else {
  898. newParts.push(code);
  899. }
  900. code = oldParts.shift();
  901. if (code === void 0) {
  902. return newParts.join("");
  903. }
  904. isNumber = !isNumber;
  905. }
  906. }
  907. const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
  908. function iconToSVG(icon, customisations) {
  909. const fullIcon = {
  910. ...defaultIconProps,
  911. ...icon
  912. };
  913. const fullCustomisations = {
  914. ...defaultIconCustomisations,
  915. ...customisations
  916. };
  917. const box = {
  918. left: fullIcon.left,
  919. top: fullIcon.top,
  920. width: fullIcon.width,
  921. height: fullIcon.height
  922. };
  923. let body = fullIcon.body;
  924. [fullIcon, fullCustomisations].forEach((props) => {
  925. const transformations = [];
  926. const hFlip = props.hFlip;
  927. const vFlip = props.vFlip;
  928. let rotation = props.rotate;
  929. if (hFlip) {
  930. if (vFlip) {
  931. rotation += 2;
  932. } else {
  933. transformations.push(
  934. "translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"
  935. );
  936. transformations.push("scale(-1 1)");
  937. box.top = box.left = 0;
  938. }
  939. } else if (vFlip) {
  940. transformations.push(
  941. "translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"
  942. );
  943. transformations.push("scale(1 -1)");
  944. box.top = box.left = 0;
  945. }
  946. let tempValue;
  947. if (rotation < 0) {
  948. rotation -= Math.floor(rotation / 4) * 4;
  949. }
  950. rotation = rotation % 4;
  951. switch (rotation) {
  952. case 1:
  953. tempValue = box.height / 2 + box.top;
  954. transformations.unshift(
  955. "rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"
  956. );
  957. break;
  958. case 2:
  959. transformations.unshift(
  960. "rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"
  961. );
  962. break;
  963. case 3:
  964. tempValue = box.width / 2 + box.left;
  965. transformations.unshift(
  966. "rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"
  967. );
  968. break;
  969. }
  970. if (rotation % 2 === 1) {
  971. if (box.left !== box.top) {
  972. tempValue = box.left;
  973. box.left = box.top;
  974. box.top = tempValue;
  975. }
  976. if (box.width !== box.height) {
  977. tempValue = box.width;
  978. box.width = box.height;
  979. box.height = tempValue;
  980. }
  981. }
  982. if (transformations.length) {
  983. body = '<g transform="' + transformations.join(" ") + '">' + body + "</g>";
  984. }
  985. });
  986. const customisationsWidth = fullCustomisations.width;
  987. const customisationsHeight = fullCustomisations.height;
  988. const boxWidth = box.width;
  989. const boxHeight = box.height;
  990. let width;
  991. let height;
  992. if (customisationsWidth === null) {
  993. height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
  994. width = calculateSize(height, boxWidth / boxHeight);
  995. } else {
  996. width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
  997. height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
  998. }
  999. const attributes = {};
  1000. const setAttr = (prop, value) => {
  1001. if (!isUnsetKeyword(value)) {
  1002. attributes[prop] = value.toString();
  1003. }
  1004. };
  1005. setAttr("width", width);
  1006. setAttr("height", height);
  1007. attributes.viewBox = box.left.toString() + " " + box.top.toString() + " " + boxWidth.toString() + " " + boxHeight.toString();
  1008. return {
  1009. attributes,
  1010. body
  1011. };
  1012. }
  1013. const regex = /\sid="(\S+)"/g;
  1014. const randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
  1015. let counter = 0;
  1016. function replaceIDs(body, prefix = randomPrefix) {
  1017. const ids = [];
  1018. let match;
  1019. while (match = regex.exec(body)) {
  1020. ids.push(match[1]);
  1021. }
  1022. if (!ids.length) {
  1023. return body;
  1024. }
  1025. const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
  1026. ids.forEach((id) => {
  1027. const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
  1028. const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  1029. body = body.replace(
  1030. // Allowed characters before id: [#;"]
  1031. // Allowed characters after id: [)"], .[a-z]
  1032. new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"),
  1033. "$1" + newID + suffix + "$3"
  1034. );
  1035. });
  1036. body = body.replace(new RegExp(suffix, "g"), "");
  1037. return body;
  1038. }
  1039. const storage = /* @__PURE__ */ Object.create(null);
  1040. function setAPIModule(provider, item) {
  1041. storage[provider] = item;
  1042. }
  1043. function getAPIModule(provider) {
  1044. return storage[provider] || storage[""];
  1045. }
  1046. function createAPIConfig(source) {
  1047. let resources;
  1048. if (typeof source.resources === "string") {
  1049. resources = [source.resources];
  1050. } else {
  1051. resources = source.resources;
  1052. if (!(resources instanceof Array) || !resources.length) {
  1053. return null;
  1054. }
  1055. }
  1056. const result = {
  1057. // API hosts
  1058. resources,
  1059. // Root path
  1060. path: source.path || "/",
  1061. // URL length limit
  1062. maxURL: source.maxURL || 500,
  1063. // Timeout before next host is used.
  1064. rotate: source.rotate || 750,
  1065. // Timeout before failing query.
  1066. timeout: source.timeout || 5e3,
  1067. // Randomise default API end point.
  1068. random: source.random === true,
  1069. // Start index
  1070. index: source.index || 0,
  1071. // Receive data after time out (used if time out kicks in first, then API module sends data anyway).
  1072. dataAfterTimeout: source.dataAfterTimeout !== false
  1073. };
  1074. return result;
  1075. }
  1076. const configStorage = /* @__PURE__ */ Object.create(null);
  1077. const fallBackAPISources = [
  1078. "https://api.simplesvg.com",
  1079. "https://api.unisvg.com"
  1080. ];
  1081. const fallBackAPI = [];
  1082. while (fallBackAPISources.length > 0) {
  1083. if (fallBackAPISources.length === 1) {
  1084. fallBackAPI.push(fallBackAPISources.shift());
  1085. } else {
  1086. if (Math.random() > 0.5) {
  1087. fallBackAPI.push(fallBackAPISources.shift());
  1088. } else {
  1089. fallBackAPI.push(fallBackAPISources.pop());
  1090. }
  1091. }
  1092. }
  1093. configStorage[""] = createAPIConfig({
  1094. resources: ["https://api.iconify.design"].concat(fallBackAPI)
  1095. });
  1096. function addAPIProvider(provider, customConfig) {
  1097. const config2 = createAPIConfig(customConfig);
  1098. if (config2 === null) {
  1099. return false;
  1100. }
  1101. configStorage[provider] = config2;
  1102. return true;
  1103. }
  1104. function getAPIConfig(provider) {
  1105. return configStorage[provider];
  1106. }
  1107. const detectFetch = () => {
  1108. let callback;
  1109. try {
  1110. callback = fetch;
  1111. if (typeof callback === "function") {
  1112. return callback;
  1113. }
  1114. } catch (err) {
  1115. }
  1116. };
  1117. let fetchModule = detectFetch();
  1118. function calculateMaxLength(provider, prefix) {
  1119. const config2 = getAPIConfig(provider);
  1120. if (!config2) {
  1121. return 0;
  1122. }
  1123. let result;
  1124. if (!config2.maxURL) {
  1125. result = 0;
  1126. } else {
  1127. let maxHostLength = 0;
  1128. config2.resources.forEach((item) => {
  1129. const host = item;
  1130. maxHostLength = Math.max(maxHostLength, host.length);
  1131. });
  1132. const url = prefix + ".json?icons=";
  1133. result = config2.maxURL - maxHostLength - config2.path.length - url.length;
  1134. }
  1135. return result;
  1136. }
  1137. function shouldAbort(status) {
  1138. return status === 404;
  1139. }
  1140. const prepare = (provider, prefix, icons) => {
  1141. const results = [];
  1142. const maxLength = calculateMaxLength(provider, prefix);
  1143. const type = "icons";
  1144. let item = {
  1145. type,
  1146. provider,
  1147. prefix,
  1148. icons: []
  1149. };
  1150. let length = 0;
  1151. icons.forEach((name, index) => {
  1152. length += name.length + 1;
  1153. if (length >= maxLength && index > 0) {
  1154. results.push(item);
  1155. item = {
  1156. type,
  1157. provider,
  1158. prefix,
  1159. icons: []
  1160. };
  1161. length = name.length;
  1162. }
  1163. item.icons.push(name);
  1164. });
  1165. results.push(item);
  1166. return results;
  1167. };
  1168. function getPath(provider) {
  1169. if (typeof provider === "string") {
  1170. const config2 = getAPIConfig(provider);
  1171. if (config2) {
  1172. return config2.path;
  1173. }
  1174. }
  1175. return "/";
  1176. }
  1177. const send = (host, params, callback) => {
  1178. if (!fetchModule) {
  1179. callback("abort", 424);
  1180. return;
  1181. }
  1182. let path = getPath(params.provider);
  1183. switch (params.type) {
  1184. case "icons": {
  1185. const prefix = params.prefix;
  1186. const icons = params.icons;
  1187. const iconsList = icons.join(",");
  1188. const urlParams = new URLSearchParams({
  1189. icons: iconsList
  1190. });
  1191. path += prefix + ".json?" + urlParams.toString();
  1192. break;
  1193. }
  1194. case "custom": {
  1195. const uri = params.uri;
  1196. path += uri.slice(0, 1) === "/" ? uri.slice(1) : uri;
  1197. break;
  1198. }
  1199. default:
  1200. callback("abort", 400);
  1201. return;
  1202. }
  1203. let defaultError = 503;
  1204. fetchModule(host + path).then((response) => {
  1205. const status = response.status;
  1206. if (status !== 200) {
  1207. setTimeout(() => {
  1208. callback(shouldAbort(status) ? "abort" : "next", status);
  1209. });
  1210. return;
  1211. }
  1212. defaultError = 501;
  1213. return response.json();
  1214. }).then((data) => {
  1215. if (typeof data !== "object" || data === null) {
  1216. setTimeout(() => {
  1217. if (data === 404) {
  1218. callback("abort", data);
  1219. } else {
  1220. callback("next", defaultError);
  1221. }
  1222. });
  1223. return;
  1224. }
  1225. setTimeout(() => {
  1226. callback("success", data);
  1227. });
  1228. }).catch(() => {
  1229. callback("next", defaultError);
  1230. });
  1231. };
  1232. const fetchAPIModule = {
  1233. prepare,
  1234. send
  1235. };
  1236. function sortIcons(icons) {
  1237. const result = {
  1238. loaded: [],
  1239. missing: [],
  1240. pending: []
  1241. };
  1242. const storage2 = /* @__PURE__ */ Object.create(null);
  1243. icons.sort((a, b) => {
  1244. if (a.provider !== b.provider) {
  1245. return a.provider.localeCompare(b.provider);
  1246. }
  1247. if (a.prefix !== b.prefix) {
  1248. return a.prefix.localeCompare(b.prefix);
  1249. }
  1250. return a.name.localeCompare(b.name);
  1251. });
  1252. let lastIcon = {
  1253. provider: "",
  1254. prefix: "",
  1255. name: ""
  1256. };
  1257. icons.forEach((icon) => {
  1258. if (lastIcon.name === icon.name && lastIcon.prefix === icon.prefix && lastIcon.provider === icon.provider) {
  1259. return;
  1260. }
  1261. lastIcon = icon;
  1262. const provider = icon.provider;
  1263. const prefix = icon.prefix;
  1264. const name = icon.name;
  1265. const providerStorage = storage2[provider] || (storage2[provider] = /* @__PURE__ */ Object.create(null));
  1266. const localStorage2 = providerStorage[prefix] || (providerStorage[prefix] = getStorage(provider, prefix));
  1267. let list;
  1268. if (name in localStorage2.icons) {
  1269. list = result.loaded;
  1270. } else if (prefix === "" || localStorage2.missing.has(name)) {
  1271. list = result.missing;
  1272. } else {
  1273. list = result.pending;
  1274. }
  1275. const item = {
  1276. provider,
  1277. prefix,
  1278. name
  1279. };
  1280. list.push(item);
  1281. });
  1282. return result;
  1283. }
  1284. function removeCallback(storages, id) {
  1285. storages.forEach((storage2) => {
  1286. const items = storage2.loaderCallbacks;
  1287. if (items) {
  1288. storage2.loaderCallbacks = items.filter((row) => row.id !== id);
  1289. }
  1290. });
  1291. }
  1292. function updateCallbacks(storage2) {
  1293. if (!storage2.pendingCallbacksFlag) {
  1294. storage2.pendingCallbacksFlag = true;
  1295. setTimeout(() => {
  1296. storage2.pendingCallbacksFlag = false;
  1297. const items = storage2.loaderCallbacks ? storage2.loaderCallbacks.slice(0) : [];
  1298. if (!items.length) {
  1299. return;
  1300. }
  1301. let hasPending = false;
  1302. const provider = storage2.provider;
  1303. const prefix = storage2.prefix;
  1304. items.forEach((item) => {
  1305. const icons = item.icons;
  1306. const oldLength = icons.pending.length;
  1307. icons.pending = icons.pending.filter((icon) => {
  1308. if (icon.prefix !== prefix) {
  1309. return true;
  1310. }
  1311. const name = icon.name;
  1312. if (storage2.icons[name]) {
  1313. icons.loaded.push({
  1314. provider,
  1315. prefix,
  1316. name
  1317. });
  1318. } else if (storage2.missing.has(name)) {
  1319. icons.missing.push({
  1320. provider,
  1321. prefix,
  1322. name
  1323. });
  1324. } else {
  1325. hasPending = true;
  1326. return true;
  1327. }
  1328. return false;
  1329. });
  1330. if (icons.pending.length !== oldLength) {
  1331. if (!hasPending) {
  1332. removeCallback([storage2], item.id);
  1333. }
  1334. item.callback(
  1335. icons.loaded.slice(0),
  1336. icons.missing.slice(0),
  1337. icons.pending.slice(0),
  1338. item.abort
  1339. );
  1340. }
  1341. });
  1342. });
  1343. }
  1344. }
  1345. let idCounter = 0;
  1346. function storeCallback(callback, icons, pendingSources) {
  1347. const id = idCounter++;
  1348. const abort = removeCallback.bind(null, pendingSources, id);
  1349. if (!icons.pending.length) {
  1350. return abort;
  1351. }
  1352. const item = {
  1353. id,
  1354. icons,
  1355. callback,
  1356. abort
  1357. };
  1358. pendingSources.forEach((storage2) => {
  1359. (storage2.loaderCallbacks || (storage2.loaderCallbacks = [])).push(item);
  1360. });
  1361. return abort;
  1362. }
  1363. function listToIcons(list, validate = true, simpleNames2 = false) {
  1364. const result = [];
  1365. list.forEach((item) => {
  1366. const icon = typeof item === "string" ? stringToIcon(item, validate, simpleNames2) : item;
  1367. if (icon) {
  1368. result.push(icon);
  1369. }
  1370. });
  1371. return result;
  1372. }
  1373. var defaultConfig = {
  1374. resources: [],
  1375. index: 0,
  1376. timeout: 2e3,
  1377. rotate: 750,
  1378. random: false,
  1379. dataAfterTimeout: false
  1380. };
  1381. function sendQuery(config2, payload, query, done) {
  1382. const resourcesCount = config2.resources.length;
  1383. const startIndex = config2.random ? Math.floor(Math.random() * resourcesCount) : config2.index;
  1384. let resources;
  1385. if (config2.random) {
  1386. let list = config2.resources.slice(0);
  1387. resources = [];
  1388. while (list.length > 1) {
  1389. const nextIndex = Math.floor(Math.random() * list.length);
  1390. resources.push(list[nextIndex]);
  1391. list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1));
  1392. }
  1393. resources = resources.concat(list);
  1394. } else {
  1395. resources = config2.resources.slice(startIndex).concat(config2.resources.slice(0, startIndex));
  1396. }
  1397. const startTime = Date.now();
  1398. let status = "pending";
  1399. let queriesSent = 0;
  1400. let lastError;
  1401. let timer = null;
  1402. let queue = [];
  1403. let doneCallbacks = [];
  1404. if (typeof done === "function") {
  1405. doneCallbacks.push(done);
  1406. }
  1407. function resetTimer() {
  1408. if (timer) {
  1409. clearTimeout(timer);
  1410. timer = null;
  1411. }
  1412. }
  1413. function abort() {
  1414. if (status === "pending") {
  1415. status = "aborted";
  1416. }
  1417. resetTimer();
  1418. queue.forEach((item) => {
  1419. if (item.status === "pending") {
  1420. item.status = "aborted";
  1421. }
  1422. });
  1423. queue = [];
  1424. }
  1425. function subscribe(callback, overwrite) {
  1426. if (overwrite) {
  1427. doneCallbacks = [];
  1428. }
  1429. if (typeof callback === "function") {
  1430. doneCallbacks.push(callback);
  1431. }
  1432. }
  1433. function getQueryStatus() {
  1434. return {
  1435. startTime,
  1436. payload,
  1437. status,
  1438. queriesSent,
  1439. queriesPending: queue.length,
  1440. subscribe,
  1441. abort
  1442. };
  1443. }
  1444. function failQuery() {
  1445. status = "failed";
  1446. doneCallbacks.forEach((callback) => {
  1447. callback(void 0, lastError);
  1448. });
  1449. }
  1450. function clearQueue() {
  1451. queue.forEach((item) => {
  1452. if (item.status === "pending") {
  1453. item.status = "aborted";
  1454. }
  1455. });
  1456. queue = [];
  1457. }
  1458. function moduleResponse(item, response, data) {
  1459. const isError = response !== "success";
  1460. queue = queue.filter((queued) => queued !== item);
  1461. switch (status) {
  1462. case "pending":
  1463. break;
  1464. case "failed":
  1465. if (isError || !config2.dataAfterTimeout) {
  1466. return;
  1467. }
  1468. break;
  1469. default:
  1470. return;
  1471. }
  1472. if (response === "abort") {
  1473. lastError = data;
  1474. failQuery();
  1475. return;
  1476. }
  1477. if (isError) {
  1478. lastError = data;
  1479. if (!queue.length) {
  1480. if (!resources.length) {
  1481. failQuery();
  1482. } else {
  1483. execNext();
  1484. }
  1485. }
  1486. return;
  1487. }
  1488. resetTimer();
  1489. clearQueue();
  1490. if (!config2.random) {
  1491. const index = config2.resources.indexOf(item.resource);
  1492. if (index !== -1 && index !== config2.index) {
  1493. config2.index = index;
  1494. }
  1495. }
  1496. status = "completed";
  1497. doneCallbacks.forEach((callback) => {
  1498. callback(data);
  1499. });
  1500. }
  1501. function execNext() {
  1502. if (status !== "pending") {
  1503. return;
  1504. }
  1505. resetTimer();
  1506. const resource = resources.shift();
  1507. if (resource === void 0) {
  1508. if (queue.length) {
  1509. timer = setTimeout(() => {
  1510. resetTimer();
  1511. if (status === "pending") {
  1512. clearQueue();
  1513. failQuery();
  1514. }
  1515. }, config2.timeout);
  1516. return;
  1517. }
  1518. failQuery();
  1519. return;
  1520. }
  1521. const item = {
  1522. status: "pending",
  1523. resource,
  1524. callback: (status2, data) => {
  1525. moduleResponse(item, status2, data);
  1526. }
  1527. };
  1528. queue.push(item);
  1529. queriesSent++;
  1530. timer = setTimeout(execNext, config2.rotate);
  1531. query(resource, payload, item.callback);
  1532. }
  1533. setTimeout(execNext);
  1534. return getQueryStatus;
  1535. }
  1536. function initRedundancy(cfg) {
  1537. const config2 = {
  1538. ...defaultConfig,
  1539. ...cfg
  1540. };
  1541. let queries = [];
  1542. function cleanup() {
  1543. queries = queries.filter((item) => item().status === "pending");
  1544. }
  1545. function query(payload, queryCallback, doneCallback) {
  1546. const query2 = sendQuery(
  1547. config2,
  1548. payload,
  1549. queryCallback,
  1550. (data, error) => {
  1551. cleanup();
  1552. if (doneCallback) {
  1553. doneCallback(data, error);
  1554. }
  1555. }
  1556. );
  1557. queries.push(query2);
  1558. return query2;
  1559. }
  1560. function find(callback) {
  1561. return queries.find((value) => {
  1562. return callback(value);
  1563. }) || null;
  1564. }
  1565. const instance = {
  1566. query,
  1567. find,
  1568. setIndex: (index) => {
  1569. config2.index = index;
  1570. },
  1571. getIndex: () => config2.index,
  1572. cleanup
  1573. };
  1574. return instance;
  1575. }
  1576. function emptyCallback$1() {
  1577. }
  1578. const redundancyCache = /* @__PURE__ */ Object.create(null);
  1579. function getRedundancyCache(provider) {
  1580. if (!redundancyCache[provider]) {
  1581. const config2 = getAPIConfig(provider);
  1582. if (!config2) {
  1583. return;
  1584. }
  1585. const redundancy = initRedundancy(config2);
  1586. const cachedReundancy = {
  1587. config: config2,
  1588. redundancy
  1589. };
  1590. redundancyCache[provider] = cachedReundancy;
  1591. }
  1592. return redundancyCache[provider];
  1593. }
  1594. function sendAPIQuery(target, query, callback) {
  1595. let redundancy;
  1596. let send2;
  1597. if (typeof target === "string") {
  1598. const api = getAPIModule(target);
  1599. if (!api) {
  1600. callback(void 0, 424);
  1601. return emptyCallback$1;
  1602. }
  1603. send2 = api.send;
  1604. const cached = getRedundancyCache(target);
  1605. if (cached) {
  1606. redundancy = cached.redundancy;
  1607. }
  1608. } else {
  1609. const config2 = createAPIConfig(target);
  1610. if (config2) {
  1611. redundancy = initRedundancy(config2);
  1612. const moduleKey = target.resources ? target.resources[0] : "";
  1613. const api = getAPIModule(moduleKey);
  1614. if (api) {
  1615. send2 = api.send;
  1616. }
  1617. }
  1618. }
  1619. if (!redundancy || !send2) {
  1620. callback(void 0, 424);
  1621. return emptyCallback$1;
  1622. }
  1623. return redundancy.query(query, send2, callback)().abort;
  1624. }
  1625. const browserCacheVersion = "iconify2";
  1626. const browserCachePrefix = "iconify";
  1627. const browserCacheCountKey = browserCachePrefix + "-count";
  1628. const browserCacheVersionKey = browserCachePrefix + "-version";
  1629. const browserStorageHour = 36e5;
  1630. const browserStorageCacheExpiration = 168;
  1631. function getStoredItem(func, key) {
  1632. try {
  1633. return func.getItem(key);
  1634. } catch (err) {
  1635. }
  1636. }
  1637. function setStoredItem(func, key, value) {
  1638. try {
  1639. func.setItem(key, value);
  1640. return true;
  1641. } catch (err) {
  1642. }
  1643. }
  1644. function removeStoredItem(func, key) {
  1645. try {
  1646. func.removeItem(key);
  1647. } catch (err) {
  1648. }
  1649. }
  1650. function setBrowserStorageItemsCount(storage2, value) {
  1651. return setStoredItem(storage2, browserCacheCountKey, value.toString());
  1652. }
  1653. function getBrowserStorageItemsCount(storage2) {
  1654. return parseInt(getStoredItem(storage2, browserCacheCountKey)) || 0;
  1655. }
  1656. const browserStorageConfig = {
  1657. local: true,
  1658. session: true
  1659. };
  1660. const browserStorageEmptyItems = {
  1661. local: /* @__PURE__ */ new Set(),
  1662. session: /* @__PURE__ */ new Set()
  1663. };
  1664. let browserStorageStatus = false;
  1665. function setBrowserStorageStatus(status) {
  1666. browserStorageStatus = status;
  1667. }
  1668. let _window = typeof window === "undefined" ? {} : window;
  1669. function getBrowserStorage(key) {
  1670. const attr = key + "Storage";
  1671. try {
  1672. if (_window && _window[attr] && typeof _window[attr].length === "number") {
  1673. return _window[attr];
  1674. }
  1675. } catch (err) {
  1676. }
  1677. browserStorageConfig[key] = false;
  1678. }
  1679. function iterateBrowserStorage(key, callback) {
  1680. const func = getBrowserStorage(key);
  1681. if (!func) {
  1682. return;
  1683. }
  1684. const version = getStoredItem(func, browserCacheVersionKey);
  1685. if (version !== browserCacheVersion) {
  1686. if (version) {
  1687. const total2 = getBrowserStorageItemsCount(func);
  1688. for (let i = 0; i < total2; i++) {
  1689. removeStoredItem(func, browserCachePrefix + i.toString());
  1690. }
  1691. }
  1692. setStoredItem(func, browserCacheVersionKey, browserCacheVersion);
  1693. setBrowserStorageItemsCount(func, 0);
  1694. return;
  1695. }
  1696. const minTime = Math.floor(Date.now() / browserStorageHour) - browserStorageCacheExpiration;
  1697. const parseItem = (index) => {
  1698. const name = browserCachePrefix + index.toString();
  1699. const item = getStoredItem(func, name);
  1700. if (typeof item !== "string") {
  1701. return;
  1702. }
  1703. try {
  1704. const data = JSON.parse(item);
  1705. 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
  1706. callback(data, index)) {
  1707. return true;
  1708. }
  1709. } catch (err) {
  1710. }
  1711. removeStoredItem(func, name);
  1712. };
  1713. let total = getBrowserStorageItemsCount(func);
  1714. for (let i = total - 1; i >= 0; i--) {
  1715. if (!parseItem(i)) {
  1716. if (i === total - 1) {
  1717. total--;
  1718. setBrowserStorageItemsCount(func, total);
  1719. } else {
  1720. browserStorageEmptyItems[key].add(i);
  1721. }
  1722. }
  1723. }
  1724. }
  1725. function initBrowserStorage() {
  1726. if (browserStorageStatus) {
  1727. return;
  1728. }
  1729. setBrowserStorageStatus(true);
  1730. for (const key in browserStorageConfig) {
  1731. iterateBrowserStorage(key, (item) => {
  1732. const iconSet = item.data;
  1733. const provider = item.provider;
  1734. const prefix = iconSet.prefix;
  1735. const storage2 = getStorage(
  1736. provider,
  1737. prefix
  1738. );
  1739. if (!addIconSet(storage2, iconSet).length) {
  1740. return false;
  1741. }
  1742. const lastModified = iconSet.lastModified || -1;
  1743. storage2.lastModifiedCached = storage2.lastModifiedCached ? Math.min(storage2.lastModifiedCached, lastModified) : lastModified;
  1744. return true;
  1745. });
  1746. }
  1747. }
  1748. function updateLastModified(storage2, lastModified) {
  1749. const lastValue = storage2.lastModifiedCached;
  1750. if (
  1751. // Matches or newer
  1752. lastValue && lastValue >= lastModified
  1753. ) {
  1754. return lastValue === lastModified;
  1755. }
  1756. storage2.lastModifiedCached = lastModified;
  1757. if (lastValue) {
  1758. for (const key in browserStorageConfig) {
  1759. iterateBrowserStorage(key, (item) => {
  1760. const iconSet = item.data;
  1761. return item.provider !== storage2.provider || iconSet.prefix !== storage2.prefix || iconSet.lastModified === lastModified;
  1762. });
  1763. }
  1764. }
  1765. return true;
  1766. }
  1767. function storeInBrowserStorage(storage2, data) {
  1768. if (!browserStorageStatus) {
  1769. initBrowserStorage();
  1770. }
  1771. function store(key) {
  1772. let func;
  1773. if (!browserStorageConfig[key] || !(func = getBrowserStorage(key))) {
  1774. return;
  1775. }
  1776. const set = browserStorageEmptyItems[key];
  1777. let index;
  1778. if (set.size) {
  1779. set.delete(index = Array.from(set).shift());
  1780. } else {
  1781. index = getBrowserStorageItemsCount(func);
  1782. if (!setBrowserStorageItemsCount(func, index + 1)) {
  1783. return;
  1784. }
  1785. }
  1786. const item = {
  1787. cached: Math.floor(Date.now() / browserStorageHour),
  1788. provider: storage2.provider,
  1789. data
  1790. };
  1791. return setStoredItem(
  1792. func,
  1793. browserCachePrefix + index.toString(),
  1794. JSON.stringify(item)
  1795. );
  1796. }
  1797. if (data.lastModified && !updateLastModified(storage2, data.lastModified)) {
  1798. return;
  1799. }
  1800. if (!Object.keys(data.icons).length) {
  1801. return;
  1802. }
  1803. if (data.not_found) {
  1804. data = Object.assign({}, data);
  1805. delete data.not_found;
  1806. }
  1807. if (!store("local")) {
  1808. store("session");
  1809. }
  1810. }
  1811. function emptyCallback() {
  1812. }
  1813. function loadedNewIcons(storage2) {
  1814. if (!storage2.iconsLoaderFlag) {
  1815. storage2.iconsLoaderFlag = true;
  1816. setTimeout(() => {
  1817. storage2.iconsLoaderFlag = false;
  1818. updateCallbacks(storage2);
  1819. });
  1820. }
  1821. }
  1822. function loadNewIcons(storage2, icons) {
  1823. if (!storage2.iconsToLoad) {
  1824. storage2.iconsToLoad = icons;
  1825. } else {
  1826. storage2.iconsToLoad = storage2.iconsToLoad.concat(icons).sort();
  1827. }
  1828. if (!storage2.iconsQueueFlag) {
  1829. storage2.iconsQueueFlag = true;
  1830. setTimeout(() => {
  1831. storage2.iconsQueueFlag = false;
  1832. const { provider, prefix } = storage2;
  1833. const icons2 = storage2.iconsToLoad;
  1834. delete storage2.iconsToLoad;
  1835. let api;
  1836. if (!icons2 || !(api = getAPIModule(provider))) {
  1837. return;
  1838. }
  1839. const params = api.prepare(provider, prefix, icons2);
  1840. params.forEach((item) => {
  1841. sendAPIQuery(provider, item, (data) => {
  1842. if (typeof data !== "object") {
  1843. item.icons.forEach((name) => {
  1844. storage2.missing.add(name);
  1845. });
  1846. } else {
  1847. try {
  1848. const parsed = addIconSet(
  1849. storage2,
  1850. data
  1851. );
  1852. if (!parsed.length) {
  1853. return;
  1854. }
  1855. const pending = storage2.pendingIcons;
  1856. if (pending) {
  1857. parsed.forEach((name) => {
  1858. pending.delete(name);
  1859. });
  1860. }
  1861. storeInBrowserStorage(storage2, data);
  1862. } catch (err) {
  1863. console.error(err);
  1864. }
  1865. }
  1866. loadedNewIcons(storage2);
  1867. });
  1868. });
  1869. });
  1870. }
  1871. }
  1872. const loadIcons = (icons, callback) => {
  1873. const cleanedIcons = listToIcons(icons, true, allowSimpleNames());
  1874. const sortedIcons = sortIcons(cleanedIcons);
  1875. if (!sortedIcons.pending.length) {
  1876. let callCallback = true;
  1877. if (callback) {
  1878. setTimeout(() => {
  1879. if (callCallback) {
  1880. callback(
  1881. sortedIcons.loaded,
  1882. sortedIcons.missing,
  1883. sortedIcons.pending,
  1884. emptyCallback
  1885. );
  1886. }
  1887. });
  1888. }
  1889. return () => {
  1890. callCallback = false;
  1891. };
  1892. }
  1893. const newIcons = /* @__PURE__ */ Object.create(null);
  1894. const sources = [];
  1895. let lastProvider, lastPrefix;
  1896. sortedIcons.pending.forEach((icon) => {
  1897. const { provider, prefix } = icon;
  1898. if (prefix === lastPrefix && provider === lastProvider) {
  1899. return;
  1900. }
  1901. lastProvider = provider;
  1902. lastPrefix = prefix;
  1903. sources.push(getStorage(provider, prefix));
  1904. const providerNewIcons = newIcons[provider] || (newIcons[provider] = /* @__PURE__ */ Object.create(null));
  1905. if (!providerNewIcons[prefix]) {
  1906. providerNewIcons[prefix] = [];
  1907. }
  1908. });
  1909. sortedIcons.pending.forEach((icon) => {
  1910. const { provider, prefix, name } = icon;
  1911. const storage2 = getStorage(provider, prefix);
  1912. const pendingQueue = storage2.pendingIcons || (storage2.pendingIcons = /* @__PURE__ */ new Set());
  1913. if (!pendingQueue.has(name)) {
  1914. pendingQueue.add(name);
  1915. newIcons[provider][prefix].push(name);
  1916. }
  1917. });
  1918. sources.forEach((storage2) => {
  1919. const { provider, prefix } = storage2;
  1920. if (newIcons[provider][prefix].length) {
  1921. loadNewIcons(storage2, newIcons[provider][prefix]);
  1922. }
  1923. });
  1924. return callback ? storeCallback(callback, sortedIcons, sources) : emptyCallback;
  1925. };
  1926. function mergeCustomisations(defaults, item) {
  1927. const result = {
  1928. ...defaults
  1929. };
  1930. for (const key in item) {
  1931. const value = item[key];
  1932. const valueType = typeof value;
  1933. if (key in defaultIconSizeCustomisations) {
  1934. if (value === null || value && (valueType === "string" || valueType === "number")) {
  1935. result[key] = value;
  1936. }
  1937. } else if (valueType === typeof result[key]) {
  1938. result[key] = key === "rotate" ? value % 4 : value;
  1939. }
  1940. }
  1941. return result;
  1942. }
  1943. const separator = /[\s,]+/;
  1944. function flipFromString(custom, flip) {
  1945. flip.split(separator).forEach((str) => {
  1946. const value = str.trim();
  1947. switch (value) {
  1948. case "horizontal":
  1949. custom.hFlip = true;
  1950. break;
  1951. case "vertical":
  1952. custom.vFlip = true;
  1953. break;
  1954. }
  1955. });
  1956. }
  1957. function rotateFromString(value, defaultValue = 0) {
  1958. const units = value.replace(/^-?[0-9.]*/, "");
  1959. function cleanup(value2) {
  1960. while (value2 < 0) {
  1961. value2 += 4;
  1962. }
  1963. return value2 % 4;
  1964. }
  1965. if (units === "") {
  1966. const num = parseInt(value);
  1967. return isNaN(num) ? 0 : cleanup(num);
  1968. } else if (units !== value) {
  1969. let split = 0;
  1970. switch (units) {
  1971. case "%":
  1972. split = 25;
  1973. break;
  1974. case "deg":
  1975. split = 90;
  1976. }
  1977. if (split) {
  1978. let num = parseFloat(value.slice(0, value.length - units.length));
  1979. if (isNaN(num)) {
  1980. return 0;
  1981. }
  1982. num = num / split;
  1983. return num % 1 === 0 ? cleanup(num) : 0;
  1984. }
  1985. }
  1986. return defaultValue;
  1987. }
  1988. function iconToHTML(body, attributes) {
  1989. let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : ' xmlns:xlink="http://www.w3.org/1999/xlink"';
  1990. for (const attr in attributes) {
  1991. renderAttribsHTML += " " + attr + '="' + attributes[attr] + '"';
  1992. }
  1993. return '<svg xmlns="http://www.w3.org/2000/svg"' + renderAttribsHTML + ">" + body + "</svg>";
  1994. }
  1995. function encodeSVGforURL(svg) {
  1996. return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ");
  1997. }
  1998. function svgToData(svg) {
  1999. return "data:image/svg+xml," + encodeSVGforURL(svg);
  2000. }
  2001. function svgToURL(svg) {
  2002. return 'url("' + svgToData(svg) + '")';
  2003. }
  2004. const defaultExtendedIconCustomisations = {
  2005. ...defaultIconCustomisations,
  2006. inline: false
  2007. };
  2008. const svgDefaults = {
  2009. "xmlns": "http://www.w3.org/2000/svg",
  2010. "xmlns:xlink": "http://www.w3.org/1999/xlink",
  2011. "aria-hidden": true,
  2012. "role": "img"
  2013. };
  2014. const commonProps = {
  2015. display: "inline-block"
  2016. };
  2017. const monotoneProps = {
  2018. backgroundColor: "currentColor"
  2019. };
  2020. const coloredProps = {
  2021. backgroundColor: "transparent"
  2022. };
  2023. const propsToAdd = {
  2024. Image: "var(--svg)",
  2025. Repeat: "no-repeat",
  2026. Size: "100% 100%"
  2027. };
  2028. const propsToAddTo = {
  2029. webkitMask: monotoneProps,
  2030. mask: monotoneProps,
  2031. background: coloredProps
  2032. };
  2033. for (const prefix in propsToAddTo) {
  2034. const list = propsToAddTo[prefix];
  2035. for (const prop in propsToAdd) {
  2036. list[prefix + prop] = propsToAdd[prop];
  2037. }
  2038. }
  2039. const customisationAliases = {};
  2040. ["horizontal", "vertical"].forEach((prefix) => {
  2041. const attr = prefix.slice(0, 1) + "Flip";
  2042. customisationAliases[prefix + "-flip"] = attr;
  2043. customisationAliases[prefix.slice(0, 1) + "-flip"] = attr;
  2044. customisationAliases[prefix + "Flip"] = attr;
  2045. });
  2046. function fixSize(value) {
  2047. return value + (value.match(/^[-0-9.]+$/) ? "px" : "");
  2048. }
  2049. const render = (icon, props) => {
  2050. const customisations = mergeCustomisations(defaultExtendedIconCustomisations, props);
  2051. const componentProps = { ...svgDefaults };
  2052. const mode = props.mode || "svg";
  2053. const style = {};
  2054. const propsStyle = props.style;
  2055. const customStyle = typeof propsStyle === "object" && !(propsStyle instanceof Array) ? propsStyle : {};
  2056. for (let key in props) {
  2057. const value = props[key];
  2058. if (value === void 0) {
  2059. continue;
  2060. }
  2061. switch (key) {
  2062. case "icon":
  2063. case "style":
  2064. case "onLoad":
  2065. case "mode":
  2066. break;
  2067. case "inline":
  2068. case "hFlip":
  2069. case "vFlip":
  2070. customisations[key] = value === true || value === "true" || value === 1;
  2071. break;
  2072. case "flip":
  2073. if (typeof value === "string") {
  2074. flipFromString(customisations, value);
  2075. }
  2076. break;
  2077. case "color":
  2078. style.color = value;
  2079. break;
  2080. case "rotate":
  2081. if (typeof value === "string") {
  2082. customisations[key] = rotateFromString(value);
  2083. } else if (typeof value === "number") {
  2084. customisations[key] = value;
  2085. }
  2086. break;
  2087. case "ariaHidden":
  2088. case "aria-hidden":
  2089. if (value !== true && value !== "true") {
  2090. delete componentProps["aria-hidden"];
  2091. }
  2092. break;
  2093. default: {
  2094. const alias = customisationAliases[key];
  2095. if (alias) {
  2096. if (value === true || value === "true" || value === 1) {
  2097. customisations[alias] = true;
  2098. }
  2099. } else if (defaultExtendedIconCustomisations[key] === void 0) {
  2100. componentProps[key] = value;
  2101. }
  2102. }
  2103. }
  2104. }
  2105. const item = iconToSVG(icon, customisations);
  2106. const renderAttribs = item.attributes;
  2107. if (customisations.inline) {
  2108. style.verticalAlign = "-0.125em";
  2109. }
  2110. if (mode === "svg") {
  2111. componentProps.style = {
  2112. ...style,
  2113. ...customStyle
  2114. };
  2115. Object.assign(componentProps, renderAttribs);
  2116. let localCounter = 0;
  2117. let id = props.id;
  2118. if (typeof id === "string") {
  2119. id = id.replace(/-/g, "_");
  2120. }
  2121. componentProps["innerHTML"] = replaceIDs(item.body, id ? () => id + "ID" + localCounter++ : "iconifyVue");
  2122. return vue.h("svg", componentProps);
  2123. }
  2124. const { body, width, height } = icon;
  2125. const useMask = mode === "mask" || (mode === "bg" ? false : body.indexOf("currentColor") !== -1);
  2126. const html = iconToHTML(body, {
  2127. ...renderAttribs,
  2128. width: width + "",
  2129. height: height + ""
  2130. });
  2131. componentProps.style = {
  2132. ...style,
  2133. "--svg": svgToURL(html),
  2134. "width": fixSize(renderAttribs.width),
  2135. "height": fixSize(renderAttribs.height),
  2136. ...commonProps,
  2137. ...useMask ? monotoneProps : coloredProps,
  2138. ...customStyle
  2139. };
  2140. return vue.h("span", componentProps);
  2141. };
  2142. allowSimpleNames(true);
  2143. setAPIModule("", fetchAPIModule);
  2144. if (typeof document !== "undefined" && typeof window !== "undefined") {
  2145. initBrowserStorage();
  2146. const _window2 = window;
  2147. if (_window2.IconifyPreload !== void 0) {
  2148. const preload = _window2.IconifyPreload;
  2149. const err = "Invalid IconifyPreload syntax.";
  2150. if (typeof preload === "object" && preload !== null) {
  2151. (preload instanceof Array ? preload : [preload]).forEach((item) => {
  2152. try {
  2153. if (
  2154. // Check if item is an object and not null/array
  2155. typeof item !== "object" || item === null || item instanceof Array || // Check for 'icons' and 'prefix'
  2156. typeof item.icons !== "object" || typeof item.prefix !== "string" || // Add icon set
  2157. !addCollection(item)
  2158. ) {
  2159. console.error(err);
  2160. }
  2161. } catch (e2) {
  2162. console.error(err);
  2163. }
  2164. });
  2165. }
  2166. }
  2167. if (_window2.IconifyProviders !== void 0) {
  2168. const providers = _window2.IconifyProviders;
  2169. if (typeof providers === "object" && providers !== null) {
  2170. for (let key in providers) {
  2171. const err = "IconifyProviders[" + key + "] is invalid.";
  2172. try {
  2173. const value = providers[key];
  2174. if (typeof value !== "object" || !value || value.resources === void 0) {
  2175. continue;
  2176. }
  2177. if (!addAPIProvider(key, value)) {
  2178. console.error(err);
  2179. }
  2180. } catch (e2) {
  2181. console.error(err);
  2182. }
  2183. }
  2184. }
  2185. }
  2186. }
  2187. const emptyIcon = {
  2188. ...defaultIconProps,
  2189. body: ""
  2190. };
  2191. const Icon = vue.defineComponent({
  2192. // Do not inherit other attributes: it is handled by render()
  2193. inheritAttrs: false,
  2194. // Set initial data
  2195. data() {
  2196. return {
  2197. // Mounted status
  2198. iconMounted: false,
  2199. // Callback counter to trigger re-render
  2200. counter: 0
  2201. };
  2202. },
  2203. mounted() {
  2204. this._name = "";
  2205. this._loadingIcon = null;
  2206. this.iconMounted = true;
  2207. },
  2208. unmounted() {
  2209. this.abortLoading();
  2210. },
  2211. methods: {
  2212. abortLoading() {
  2213. if (this._loadingIcon) {
  2214. this._loadingIcon.abort();
  2215. this._loadingIcon = null;
  2216. }
  2217. },
  2218. // Get data for icon to render or null
  2219. getIcon(icon, onload) {
  2220. if (typeof icon === "object" && icon !== null && typeof icon.body === "string") {
  2221. this._name = "";
  2222. this.abortLoading();
  2223. return {
  2224. data: icon
  2225. };
  2226. }
  2227. let iconName;
  2228. if (typeof icon !== "string" || (iconName = stringToIcon(icon, false, true)) === null) {
  2229. this.abortLoading();
  2230. return null;
  2231. }
  2232. const data = getIconData(iconName);
  2233. if (!data) {
  2234. if (!this._loadingIcon || this._loadingIcon.name !== icon) {
  2235. this.abortLoading();
  2236. this._name = "";
  2237. if (data !== null) {
  2238. this._loadingIcon = {
  2239. name: icon,
  2240. abort: loadIcons([iconName], () => {
  2241. this.counter++;
  2242. })
  2243. };
  2244. }
  2245. }
  2246. return null;
  2247. }
  2248. this.abortLoading();
  2249. if (this._name !== icon) {
  2250. this._name = icon;
  2251. if (onload) {
  2252. onload(icon);
  2253. }
  2254. }
  2255. const classes = ["iconify"];
  2256. if (iconName.prefix !== "") {
  2257. classes.push("iconify--" + iconName.prefix);
  2258. }
  2259. if (iconName.provider !== "") {
  2260. classes.push("iconify--" + iconName.provider);
  2261. }
  2262. return { data, classes };
  2263. }
  2264. },
  2265. // Render icon
  2266. render() {
  2267. this.counter;
  2268. const props = this.$attrs;
  2269. const icon = this.iconMounted ? this.getIcon(props.icon, props.onLoad) : null;
  2270. if (!icon) {
  2271. return render(emptyIcon, props);
  2272. }
  2273. let newProps = props;
  2274. if (icon.classes) {
  2275. newProps = {
  2276. ...props,
  2277. class: (typeof props["class"] === "string" ? props["class"] + " " : "") + icon.classes.join(" ")
  2278. };
  2279. }
  2280. return render({
  2281. ...defaultIconProps,
  2282. ...icon.data
  2283. }, newProps);
  2284. }
  2285. });
  2286. const _hoisted_1$i = { class: "display-type" };
  2287. const _hoisted_2$f = { style: { "position": "relative" } };
  2288. const _hoisted_3$c = {
  2289. key: 0,
  2290. class: "type-list"
  2291. };
  2292. const _sfc_main$j = /* @__PURE__ */ vue.defineComponent({
  2293. __name: "BaseSelect",
  2294. props: {
  2295. displayType: {}
  2296. },
  2297. emits: ["update:displayType"],
  2298. setup(__props, { emit: __emit }) {
  2299. const props = __props;
  2300. const emit = __emit;
  2301. let state = vue.reactive({
  2302. showChangeDisplayType: false,
  2303. lastDisplayType: null
  2304. });
  2305. function changeOption(item) {
  2306. if (![CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2307. state.lastDisplayType = props.displayType;
  2308. }
  2309. emit("update:displayType", item);
  2310. state.showChangeDisplayType = false;
  2311. }
  2312. function clickDisplayType() {
  2313. if ([CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2314. return changeOption(state.lastDisplayType ?? CommentDisplayType.FloorInFloorNoCallUser);
  2315. }
  2316. state.showChangeDisplayType = !state.showChangeDisplayType;
  2317. }
  2318. const currentDisplayType = vue.computed(() => {
  2319. let judge = props.displayType;
  2320. if ([CommentDisplayType.New, CommentDisplayType.Like].includes(props.displayType)) {
  2321. judge = state.lastDisplayType;
  2322. }
  2323. switch (judge) {
  2324. case CommentDisplayType.FloorInFloorNoCallUser:
  2325. return "楼中楼";
  2326. case CommentDisplayType.FloorInFloor:
  2327. return "楼中楼(@)";
  2328. case CommentDisplayType.FloorInFloorNested:
  2329. return "冗余楼中楼";
  2330. case CommentDisplayType.V2exOrigin:
  2331. return "V2原版";
  2332. case CommentDisplayType.OnlyOp:
  2333. return "只看楼主";
  2334. default:
  2335. return "楼中楼";
  2336. }
  2337. });
  2338. return (_ctx, _cache) => {
  2339. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$i, [
  2340. vue.createElementVNode("div", {
  2341. class: vue.normalizeClass(["type", _ctx.displayType === vue.unref(CommentDisplayType).New && "active"]),
  2342. onClick: _cache[0] || (_cache[0] = ($event) => changeOption(vue.unref(CommentDisplayType).New))
  2343. }, "最新 ", 2),
  2344. vue.createElementVNode("div", {
  2345. class: vue.normalizeClass(["type", _ctx.displayType === vue.unref(CommentDisplayType).Like && "active"]),
  2346. onClick: _cache[1] || (_cache[1] = ($event) => changeOption(vue.unref(CommentDisplayType).Like))
  2347. }, "最热 ", 2),
  2348. vue.createElementVNode("div", _hoisted_2$f, [
  2349. vue.createElementVNode("div", {
  2350. class: vue.normalizeClass(["type", ![vue.unref(CommentDisplayType).New, vue.unref(CommentDisplayType).Like].includes(_ctx.displayType) && "active"]),
  2351. onClick: clickDisplayType
  2352. }, [
  2353. vue.createElementVNode("span", null, vue.toDisplayString(currentDisplayType.value), 1),
  2354. vue.createVNode(vue.unref(Icon), { icon: "mingcute:down-line" })
  2355. ], 2),
  2356. vue.unref(state).showChangeDisplayType ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$c, [
  2357. vue.createElementVNode("div", {
  2358. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloorNoCallUser && "active"]),
  2359. onClick: _cache[2] || (_cache[2] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloorNoCallUser), ["stop"]))
  2360. }, "楼中楼 ", 2),
  2361. vue.createElementVNode("div", {
  2362. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloor && "active"]),
  2363. onClick: _cache[3] || (_cache[3] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloor), ["stop"]))
  2364. }, "楼中楼(@) ", 2),
  2365. vue.createElementVNode("div", {
  2366. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).FloorInFloorNested && "active"]),
  2367. onClick: _cache[4] || (_cache[4] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).FloorInFloorNested), ["stop"]))
  2368. }, "冗余楼中楼 ", 2),
  2369. vue.createElementVNode("div", {
  2370. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).OnlyOp && "active"]),
  2371. onClick: _cache[5] || (_cache[5] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).OnlyOp), ["stop"]))
  2372. }, "只看楼主 ", 2),
  2373. vue.createElementVNode("div", {
  2374. class: vue.normalizeClass(["item", _ctx.displayType === vue.unref(CommentDisplayType).V2exOrigin && "active"]),
  2375. onClick: _cache[6] || (_cache[6] = vue.withModifiers(($event) => changeOption(vue.unref(CommentDisplayType).V2exOrigin), ["stop"]))
  2376. }, "V2原版 ", 2)
  2377. ])) : vue.createCommentVNode("", true)
  2378. ])
  2379. ]);
  2380. };
  2381. }
  2382. });
  2383. const BaseSelect = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-e4f684be"]]);
  2384. const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
  2385. __name: "BaseLoading",
  2386. props: {
  2387. size: { default: "normal" }
  2388. },
  2389. setup(__props) {
  2390. return (_ctx, _cache) => {
  2391. return vue.openBlock(), vue.createElementBlock("div", {
  2392. class: vue.normalizeClass(["loading", [_ctx.size]])
  2393. }, null, 2);
  2394. };
  2395. }
  2396. });
  2397. const BaseLoading = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-2697baa2"]]);
  2398. const _hoisted_1$h = {
  2399. key: 1,
  2400. class: "key-notice"
  2401. };
  2402. const _hoisted_2$e = { class: "key" };
  2403. const _sfc_main$h = /* @__PURE__ */ vue.defineComponent({
  2404. __name: "BaseButton",
  2405. props: {
  2406. keyboard: {},
  2407. active: { type: Boolean },
  2408. disabled: { type: Boolean },
  2409. loading: { type: Boolean },
  2410. size: { default: "normal" },
  2411. type: { default: "primary" }
  2412. },
  2413. emits: ["click"],
  2414. setup(__props) {
  2415. return (_ctx, _cache) => {
  2416. return vue.openBlock(), vue.createBlock(Tooltip, {
  2417. disabled: !_ctx.keyboard,
  2418. title: `快捷键: ${_ctx.keyboard}`
  2419. }, {
  2420. default: vue.withCtx(() => [
  2421. vue.createElementVNode("div", vue.mergeProps({ class: "base-button" }, _ctx.$attrs, {
  2422. onClick: _cache[0] || (_cache[0] = (e2) => !_ctx.disabled && !_ctx.loading && _ctx.$emit("click", e2)),
  2423. class: [
  2424. _ctx.active && "active",
  2425. _ctx.size,
  2426. _ctx.type,
  2427. (_ctx.disabled || _ctx.loading) && "disabled",
  2428. !_ctx.disabled && "hvr-grow"
  2429. ]
  2430. }), [
  2431. vue.createElementVNode("span", {
  2432. style: vue.normalizeStyle({ opacity: _ctx.loading ? 0 : 1 })
  2433. }, [
  2434. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  2435. ], 4),
  2436. _ctx.loading ? (vue.openBlock(), vue.createBlock(BaseLoading, {
  2437. key: 0,
  2438. size: "small"
  2439. })) : vue.createCommentVNode("", true),
  2440. _ctx.keyboard ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$h, [
  2441. vue.createElementVNode("span", _hoisted_2$e, vue.toDisplayString(_ctx.keyboard), 1)
  2442. ])) : vue.createCommentVNode("", true)
  2443. ], 16)
  2444. ]),
  2445. _: 3
  2446. }, 8, ["disabled", "title"]);
  2447. };
  2448. }
  2449. });
  2450. const BaseButton = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["__scopeId", "data-v-5a7d79ba"]]);
  2451. const _sfc_main$g = {
  2452. name: "PopConfirm",
  2453. components: { BaseButton },
  2454. props: {
  2455. title: {
  2456. type: String,
  2457. default() {
  2458. return "";
  2459. }
  2460. },
  2461. disabled: {
  2462. type: Boolean,
  2463. default() {
  2464. return false;
  2465. }
  2466. }
  2467. },
  2468. data() {
  2469. return {
  2470. show: false
  2471. };
  2472. },
  2473. methods: {
  2474. showPop(e2) {
  2475. if (this.disabled)
  2476. return;
  2477. let rect = e2.target.getBoundingClientRect();
  2478. this.show = true;
  2479. vue.nextTick(() => {
  2480. this.$refs.tip.style.top = rect.top + "px";
  2481. this.$refs.tip.style.left = rect.left + rect.width / 2 - 50 + "px";
  2482. });
  2483. },
  2484. confirm() {
  2485. this.show = false;
  2486. this.$emit("confirm");
  2487. },
  2488. cancel() {
  2489. this.show = false;
  2490. this.$emit("cancel");
  2491. }
  2492. }
  2493. };
  2494. const _hoisted_1$g = { class: "pop-confirm" };
  2495. const _hoisted_2$d = {
  2496. key: 0,
  2497. ref: "tip",
  2498. class: "pop-confirm-content"
  2499. };
  2500. const _hoisted_3$b = { class: "text" };
  2501. const _hoisted_4$b = { class: "options" };
  2502. function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
  2503. const _component_BaseButton = vue.resolveComponent("BaseButton");
  2504. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, [
  2505. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  2506. vue.createVNode(vue.Transition, null, {
  2507. default: vue.withCtx(() => [
  2508. $data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$d, [
  2509. vue.createElementVNode("div", _hoisted_3$b, vue.toDisplayString($props.title), 1),
  2510. vue.createElementVNode("div", _hoisted_4$b, [
  2511. vue.createVNode(_component_BaseButton, {
  2512. type: "link",
  2513. size: "small",
  2514. onClick: $options.cancel
  2515. }, {
  2516. default: vue.withCtx(() => [
  2517. vue.createTextVNode("取消")
  2518. ]),
  2519. _: 1
  2520. }, 8, ["onClick"]),
  2521. vue.createVNode(_component_BaseButton, {
  2522. size: "small",
  2523. onClick: $options.confirm
  2524. }, {
  2525. default: vue.withCtx(() => [
  2526. vue.createTextVNode("确认")
  2527. ]),
  2528. _: 1
  2529. }, 8, ["onClick"])
  2530. ])
  2531. ], 512)) : vue.createCommentVNode("", true)
  2532. ]),
  2533. _: 1
  2534. })
  2535. ])),
  2536. vue.createElementVNode("span", {
  2537. onClick: _cache[0] || (_cache[0] = (...args) => $options.showPop && $options.showPop(...args))
  2538. }, [
  2539. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  2540. ])
  2541. ]);
  2542. }
  2543. const PopConfirm = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["render", _sfc_render$9], ["__scopeId", "data-v-7d29b3cc"]]);
  2544. const _sfc_main$f = {
  2545. name: "Setting",
  2546. components: {
  2547. BaseButton,
  2548. PopConfirm,
  2549. Icon,
  2550. BaseSelect,
  2551. BaseSwitch,
  2552. Tooltip
  2553. },
  2554. inject: ["isNight"],
  2555. props: {
  2556. show: {
  2557. type: Boolean,
  2558. default() {
  2559. return false;
  2560. }
  2561. }
  2562. },
  2563. data() {
  2564. return {
  2565. tabIndex: 0
  2566. };
  2567. },
  2568. methods: {
  2569. confirm() {
  2570. this.close();
  2571. this.$emit("confirm");
  2572. },
  2573. close() {
  2574. this.$emit("update:show", false);
  2575. }
  2576. }
  2577. };
  2578. const _withScopeId$a = (n2) => (vue.pushScopeId("data-v-cb13d533"), n2 = n2(), vue.popScopeId(), n2);
  2579. const _hoisted_1$f = {
  2580. key: 0,
  2581. class: "setting-modal modal"
  2582. };
  2583. const _hoisted_2$c = { class: "modal-root" };
  2584. const _hoisted_3$a = { class: "modal-header" };
  2585. const _hoisted_4$a = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 使用需知 ", -1));
  2586. const _hoisted_5$8 = { class: "body" };
  2587. const _hoisted_6$8 = /* @__PURE__ */ _withScopeId$a(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "modal-content" }, [
  2588. /* @__PURE__ */ vue.createElementVNode("div", null, "开启此功能会带来以下影响"),
  2589. /* @__PURE__ */ vue.createElementVNode("div", null, "缺点"),
  2590. /* @__PURE__ */ vue.createElementVNode("div", { style: { "color": "red" } }, [
  2591. /* @__PURE__ */ vue.createElementVNode("div", null, "1、你的IP可能会被封禁"),
  2592. /* @__PURE__ */ vue.createElementVNode("div", null, "2、消耗更多流量,给服务器带来更大的负担"),
  2593. /* @__PURE__ */ vue.createElementVNode("div", null, "3、你的V站浏览进度条会变快")
  2594. ]),
  2595. /* @__PURE__ */ vue.createElementVNode("div", null, "优点"),
  2596. /* @__PURE__ */ vue.createElementVNode("div", null, "1、卡片模式,无需打开主题即可查看内容"),
  2597. /* @__PURE__ */ vue.createElementVNode("div", null, "2、打开主题时提前预览正文内容,无需等待加载"),
  2598. /* @__PURE__ */ vue.createElementVNode("div", null, "原理"),
  2599. /* @__PURE__ */ vue.createElementVNode("div", null, "1、解析列表所有主题ID,批量调用show.json接口,获取对应主题的正文"),
  2600. /* @__PURE__ */ vue.createElementVNode("div", null, "2、请求的主题数据会缓存到本地,不会重复请求,超过3天的数据会删除"),
  2601. /* @__PURE__ */ vue.createElementVNode("div", null, "3、前面4条会并发请求,4条以后的一秒请求一条")
  2602. ], -1));
  2603. const _hoisted_7$7 = { class: "btns" };
  2604. function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
  2605. const _component_Icon = vue.resolveComponent("Icon");
  2606. const _component_BaseButton = vue.resolveComponent("BaseButton");
  2607. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  2608. default: vue.withCtx(() => [
  2609. $props.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$f, [
  2610. vue.createElementVNode("div", {
  2611. class: "mask",
  2612. onClick: _cache[0] || (_cache[0] = (...args) => $options.close && $options.close(...args))
  2613. }),
  2614. vue.createElementVNode("div", _hoisted_2$c, [
  2615. vue.createElementVNode("div", _hoisted_3$a, [
  2616. _hoisted_4$a,
  2617. vue.createVNode(_component_Icon, {
  2618. icon: "ic:round-close",
  2619. onClick: $options.close
  2620. }, null, 8, ["onClick"])
  2621. ]),
  2622. vue.createElementVNode("div", _hoisted_5$8, [
  2623. _hoisted_6$8,
  2624. vue.createElementVNode("div", _hoisted_7$7, [
  2625. vue.createVNode(_component_BaseButton, {
  2626. type: "link",
  2627. onClick: $options.close
  2628. }, {
  2629. default: vue.withCtx(() => [
  2630. vue.createTextVNode("不同意")
  2631. ]),
  2632. _: 1
  2633. }, 8, ["onClick"]),
  2634. vue.createVNode(_component_BaseButton, { onClick: $options.confirm }, {
  2635. default: vue.withCtx(() => [
  2636. vue.createTextVNode("同意")
  2637. ]),
  2638. _: 1
  2639. }, 8, ["onClick"])
  2640. ])
  2641. ])
  2642. ])
  2643. ])) : vue.createCommentVNode("", true)
  2644. ]),
  2645. _: 1
  2646. });
  2647. }
  2648. const NoticeModal = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["render", _sfc_render$8], ["__scopeId", "data-v-cb13d533"]]);
  2649. const _sfc_main$e = {
  2650. name: "Setting",
  2651. components: {
  2652. NoticeModal,
  2653. PopConfirm,
  2654. Icon,
  2655. BaseSelect,
  2656. BaseSwitch,
  2657. Tooltip
  2658. },
  2659. inject: ["isNight"],
  2660. props: {
  2661. modelValue: {
  2662. type: Object,
  2663. default() {
  2664. return {};
  2665. }
  2666. },
  2667. show: {
  2668. type: Boolean,
  2669. default() {
  2670. return false;
  2671. }
  2672. }
  2673. },
  2674. data() {
  2675. return {
  2676. tabIndex: 0,
  2677. config: window.clone(this.modelValue),
  2678. showNotice: false
  2679. };
  2680. },
  2681. computed: {
  2682. DefaultVal() {
  2683. return DefaultVal;
  2684. },
  2685. CommentDisplayType() {
  2686. return CommentDisplayType;
  2687. },
  2688. isNew() {
  2689. return this.config.version < DefaultVal.currentVersion;
  2690. }
  2691. },
  2692. watch: {
  2693. config: {
  2694. handler(n2) {
  2695. n2.topReplyLoveMinCount = Math.trunc(n2.topReplyLoveMinCount);
  2696. if (n2.topReplyLoveMinCount < 0) {
  2697. n2.topReplyLoveMinCount = 1;
  2698. }
  2699. this.$emit("update:modelValue", n2);
  2700. },
  2701. deep: true
  2702. }
  2703. },
  2704. methods: {
  2705. close() {
  2706. this.config.version = DefaultVal.currentVersion;
  2707. this.$emit("update:show", false);
  2708. }
  2709. }
  2710. };
  2711. const _withScopeId$9 = (n2) => (vue.pushScopeId("data-v-df0e0e8f"), n2 = n2(), vue.popScopeId(), n2);
  2712. const _hoisted_1$e = {
  2713. key: 0,
  2714. class: "setting-modal modal"
  2715. };
  2716. const _hoisted_2$b = { class: "modal-root" };
  2717. const _hoisted_3$9 = { class: "modal-header" };
  2718. const _hoisted_4$9 = { class: "title" };
  2719. const _hoisted_5$7 = { class: "small" };
  2720. const _hoisted_6$7 = ["href"];
  2721. const _hoisted_7$6 = { class: "body" };
  2722. const _hoisted_8$6 = { class: "left" };
  2723. const _hoisted_9$6 = { class: "tabs" };
  2724. const _hoisted_10$5 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "列表设置", -1));
  2725. const _hoisted_11$5 = [
  2726. _hoisted_10$5
  2727. ];
  2728. const _hoisted_12$5 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "主题设置", -1));
  2729. const _hoisted_13$5 = [
  2730. _hoisted_12$5
  2731. ];
  2732. const _hoisted_14$5 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "其他设置", -1));
  2733. const _hoisted_15$4 = [
  2734. _hoisted_14$5
  2735. ];
  2736. const _hoisted_16$4 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("span", null, "关于脚本", -1));
  2737. const _hoisted_17$3 = [
  2738. _hoisted_16$4
  2739. ];
  2740. const _hoisted_18$3 = { class: "icons" };
  2741. const _hoisted_19$3 = ["href"];
  2742. const _hoisted_20$2 = ["href"];
  2743. const _hoisted_21$2 = { class: "modal-content" };
  2744. const _hoisted_22$2 = { class: "scroll" };
  2745. const _hoisted_23$2 = { key: 0 };
  2746. const _hoisted_24$2 = { class: "row" };
  2747. const _hoisted_25$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "列表展示方式", -1));
  2748. const _hoisted_26$1 = { class: "wrapper" };
  2749. const _hoisted_27$1 = { class: "radio-group2" };
  2750. const _hoisted_28$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  2751. const _hoisted_29$1 = { class: "row" };
  2752. const _hoisted_30$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "主题弹框显示", -1));
  2753. const _hoisted_31$1 = { class: "wrapper" };
  2754. const _hoisted_32$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  2755. /* @__PURE__ */ vue.createTextVNode(" 开启此选项后,主题会"),
  2756. /* @__PURE__ */ vue.createElementVNode("span", { class: "danger" }, "始终"),
  2757. /* @__PURE__ */ vue.createTextVNode("以弹框的方式显示。优先级大于“新标签页打开链接” ")
  2758. ], -1));
  2759. const _hoisted_33$1 = { class: "row" };
  2760. const _hoisted_34$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "新标签页打开链接", -1));
  2761. const _hoisted_35$1 = { class: "wrapper" };
  2762. const _hoisted_36$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 网页上所有链接通过新标签页打开 ", -1));
  2763. const _hoisted_37$1 = { class: "row" };
  2764. const _hoisted_38$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "打开新标签页时立即切换过去", -1));
  2765. const _hoisted_39$1 = { class: "wrapper" };
  2766. const _hoisted_40$1 = { key: 1 };
  2767. const _hoisted_41$1 = { class: "row" };
  2768. const _hoisted_42$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "显示回复展示方式", -1));
  2769. const _hoisted_43$1 = { class: "wrapper" };
  2770. const _hoisted_44$1 = { class: "row" };
  2771. const _hoisted_45$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "回复展示方式", -1));
  2772. const _hoisted_46$1 = { class: "wrapper" };
  2773. const _hoisted_47$1 = { class: "row" };
  2774. const _hoisted_48$1 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "单独打开主题时默认显示楼中楼", -1));
  2775. const _hoisted_49$1 = { class: "wrapper" };
  2776. const _hoisted_50 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 单独打开这种地址 https://v2ex.com/t/xxxx 时,是否默认显示楼中楼 ", -1));
  2777. const _hoisted_51 = { class: "row" };
  2778. const _hoisted_52 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "点击左右两侧透明处关闭主题详情弹框", -1));
  2779. const _hoisted_53 = { class: "wrapper" };
  2780. const _hoisted_54 = { class: "row" };
  2781. const _hoisted_55 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "正文超长自动折叠", -1));
  2782. const _hoisted_56 = { class: "wrapper" };
  2783. const _hoisted_57 = { class: "row" };
  2784. const _hoisted_58 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "主题宽度", -1));
  2785. const _hoisted_59 = { class: "wrapper" };
  2786. const _hoisted_60 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  2787. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则默认宽度为77rem。接受合法的width值: "),
  2788. /* @__PURE__ */ vue.createElementVNode("a", {
  2789. href: "https://vue3js.cn/interview/css/em_px_rem_vh_vw.html#%E4%BA%8C%E3%80%81%E5%8D%95%E4%BD%8D",
  2790. target: "_blank"
  2791. }, "rem、px、vw、vh(点此查看)"),
  2792. /* @__PURE__ */ vue.createTextVNode("。 vw代表屏幕百分比,如想要屏幕的66%,请填写66vw ")
  2793. ], -1));
  2794. const _hoisted_61 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " 提示:此项设置以后,单独打开详情页时会出现主题突然变宽(窄)的问题,暂时无解 ", -1));
  2795. const _hoisted_62 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  2796. const _hoisted_63 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "row" }, [
  2797. /* @__PURE__ */ vue.createElementVNode("label", { class: "main-title" }, "高赞回复")
  2798. ], -1));
  2799. const _hoisted_64 = { class: "row" };
  2800. const _hoisted_65 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "显示高赞回复", -1));
  2801. const _hoisted_66 = { class: "wrapper" };
  2802. const _hoisted_67 = { class: "row" };
  2803. const _hoisted_68 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "最多显示多少个高赞回复", -1));
  2804. const _hoisted_69 = { class: "wrapper" };
  2805. const _hoisted_70 = { class: "row" };
  2806. const _hoisted_71 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "最少需要多少赞才能被判定为高赞", -1));
  2807. const _hoisted_72 = { class: "wrapper" };
  2808. const _hoisted_73 = { key: 2 };
  2809. const _hoisted_74 = { class: "row" };
  2810. const _hoisted_75 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "用户打标签(跨平台,数据保存在自己的记事本):", -1));
  2811. const _hoisted_76 = { class: "wrapper" };
  2812. const _hoisted_77 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 2024-01-27提示:此功能暂时无法使用 ", -1));
  2813. const _hoisted_78 = { class: "row" };
  2814. const _hoisted_79 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "划词显示Base64解码框", -1));
  2815. const _hoisted_80 = { class: "wrapper" };
  2816. const _hoisted_81 = { class: "row" };
  2817. const _hoisted_82 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自动签到", -1));
  2818. const _hoisted_83 = { class: "wrapper" };
  2819. const _hoisted_84 = { class: "row" };
  2820. const _hoisted_85 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "自定义背景", -1));
  2821. const _hoisted_86 = { class: "wrapper" };
  2822. const _hoisted_87 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, [
  2823. /* @__PURE__ */ vue.createTextVNode(" 未设定此值时,则背景颜色默认为 #e2e2e2。接受一个合法的css color值:例如"),
  2824. /* @__PURE__ */ vue.createElementVNode("a", {
  2825. href: "https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value",
  2826. target: "_blank"
  2827. }, "red、#ffffff、rgb(222,222,22)(点此查看)"),
  2828. /* @__PURE__ */ vue.createTextVNode("等等。 ")
  2829. ], -1));
  2830. const _hoisted_88 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc danger" }, " 提示:此项需要刷新页面才能生效 ", -1));
  2831. const _hoisted_89 = { class: "row" };
  2832. const _hoisted_90 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("label", { class: "item-title" }, "收藏时提醒添加到书签", -1));
  2833. const _hoisted_91 = { class: "wrapper" };
  2834. const _hoisted_92 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "desc" }, " V站帐号一旦被封禁,则无法登录,无法查看账号收藏了 ", -1));
  2835. const _hoisted_93 = { key: 3 };
  2836. const _hoisted_94 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("h1", null, "V2EX Next", -1));
  2837. const _hoisted_95 = { class: "project-desc" };
  2838. const _hoisted_96 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("div", null, [
  2839. /* @__PURE__ */ vue.createTextVNode(" 本项目完全开源,已支持移动端!"),
  2840. /* @__PURE__ */ vue.createElementVNode("b", null, "好用请大家多多点Star!")
  2841. ], -1));
  2842. const _hoisted_97 = /* @__PURE__ */ _withScopeId$9(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  2843. const _hoisted_98 = { style: { "line-height": "2" } };
  2844. const _hoisted_99 = ["href"];
  2845. const _hoisted_100 = ["href"];
  2846. const _hoisted_101 = ["href"];
  2847. const _hoisted_102 = ["href"];
  2848. const _hoisted_103 = ["href"];
  2849. const _hoisted_104 = ["href"];
  2850. function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
  2851. const _component_Icon = vue.resolveComponent("Icon");
  2852. const _component_BaseSwitch = vue.resolveComponent("BaseSwitch");
  2853. const _component_BaseSelect = vue.resolveComponent("BaseSelect");
  2854. const _component_NoticeModal = vue.resolveComponent("NoticeModal");
  2855. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  2856. default: vue.withCtx(() => [
  2857. $props.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$e, [
  2858. vue.createElementVNode("div", {
  2859. class: "mask",
  2860. onClick: _cache[0] || (_cache[0] = (...args) => $options.close && $options.close(...args))
  2861. }),
  2862. vue.createElementVNode("div", _hoisted_2$b, [
  2863. vue.createElementVNode("div", _hoisted_3$9, [
  2864. vue.createElementVNode("div", _hoisted_4$9, [
  2865. vue.createTextVNode(" 脚本设置 "),
  2866. vue.createElementVNode("div", _hoisted_5$7, [
  2867. vue.createElementVNode("a", {
  2868. href: $options.DefaultVal.mobileScript,
  2869. target: "_blank"
  2870. }, "(脚本现已支持移动端!)", 8, _hoisted_6$7)
  2871. ])
  2872. ]),
  2873. vue.createVNode(_component_Icon, {
  2874. icon: "ic:round-close",
  2875. onClick: $options.close
  2876. }, null, 8, ["onClick"])
  2877. ]),
  2878. vue.createElementVNode("div", _hoisted_7$6, [
  2879. vue.createElementVNode("div", _hoisted_8$6, [
  2880. vue.createElementVNode("div", _hoisted_9$6, [
  2881. vue.createElementVNode("div", {
  2882. class: vue.normalizeClass(["tab", $data.tabIndex === 0 && "active"]),
  2883. onClick: _cache[1] || (_cache[1] = ($event) => $data.tabIndex = 0)
  2884. }, _hoisted_11$5, 2),
  2885. vue.createElementVNode("div", {
  2886. class: vue.normalizeClass(["tab", $data.tabIndex === 1 && "active"]),
  2887. onClick: _cache[2] || (_cache[2] = ($event) => $data.tabIndex = 1)
  2888. }, _hoisted_13$5, 2),
  2889. vue.createElementVNode("div", {
  2890. class: vue.normalizeClass(["tab", $data.tabIndex === 2 && "active"]),
  2891. onClick: _cache[3] || (_cache[3] = ($event) => $data.tabIndex = 2)
  2892. }, _hoisted_15$4, 2),
  2893. vue.createElementVNode("div", {
  2894. class: vue.normalizeClass(["tab", $data.tabIndex === 3 && "active"]),
  2895. onClick: _cache[4] || (_cache[4] = ($event) => $data.tabIndex = 3)
  2896. }, _hoisted_17$3, 2)
  2897. ]),
  2898. vue.createElementVNode("div", _hoisted_18$3, [
  2899. vue.createElementVNode("a", {
  2900. href: $options.DefaultVal.git,
  2901. target: "_blank"
  2902. }, [
  2903. vue.createVNode(_component_Icon, { icon: "mdi:github" })
  2904. ], 8, _hoisted_19$3),
  2905. vue.createElementVNode("a", {
  2906. href: $options.DefaultVal.homeUrl,
  2907. target: "_blank"
  2908. }, [
  2909. vue.createVNode(_component_Icon, { icon: "iconamoon:home-light" })
  2910. ], 8, _hoisted_20$2)
  2911. ])
  2912. ]),
  2913. vue.createElementVNode("div", _hoisted_21$2, [
  2914. vue.createElementVNode("div", _hoisted_22$2, [
  2915. $data.tabIndex === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_23$2, [
  2916. vue.createElementVNode("div", _hoisted_24$2, [
  2917. _hoisted_25$1,
  2918. vue.createElementVNode("div", _hoisted_26$1, [
  2919. vue.createElementVNode("div", _hoisted_27$1, [
  2920. vue.createElementVNode("div", {
  2921. class: vue.normalizeClass(["radio", $data.config.viewType === "simple" ? "active" : ""]),
  2922. onClick: _cache[5] || (_cache[5] = ($event) => $data.config.viewType = "simple")
  2923. }, "简洁 ", 2),
  2924. vue.createElementVNode("div", {
  2925. class: vue.normalizeClass(["radio", $data.config.viewType === "table" ? "active" : ""]),
  2926. onClick: _cache[6] || (_cache[6] = ($event) => $data.config.viewType = "table")
  2927. }, "表格 ", 2),
  2928. vue.createElementVNode("div", {
  2929. class: vue.normalizeClass(["radio", $data.config.viewType === "card" ? "active" : ""]),
  2930. onClick: _cache[7] || (_cache[7] = ($event) => $data.showNotice = true)
  2931. }, "卡片 ", 2)
  2932. ])
  2933. ])
  2934. ]),
  2935. _hoisted_28$1,
  2936. vue.createElementVNode("div", _hoisted_29$1, [
  2937. _hoisted_30$1,
  2938. vue.createElementVNode("div", _hoisted_31$1, [
  2939. vue.createVNode(_component_BaseSwitch, {
  2940. modelValue: $data.config.clickPostItemOpenDetail,
  2941. "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => $data.config.clickPostItemOpenDetail = $event)
  2942. }, null, 8, ["modelValue"])
  2943. ])
  2944. ]),
  2945. _hoisted_32$1,
  2946. vue.createElementVNode("div", _hoisted_33$1, [
  2947. _hoisted_34$1,
  2948. vue.createElementVNode("div", _hoisted_35$1, [
  2949. vue.createVNode(_component_BaseSwitch, {
  2950. modelValue: $data.config.newTabOpen,
  2951. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => $data.config.newTabOpen = $event)
  2952. }, null, 8, ["modelValue"])
  2953. ])
  2954. ]),
  2955. _hoisted_36$1,
  2956. vue.createElementVNode("div", _hoisted_37$1, [
  2957. _hoisted_38$1,
  2958. vue.createElementVNode("div", _hoisted_39$1, [
  2959. vue.createVNode(_component_BaseSwitch, {
  2960. modelValue: $data.config.newTabOpenActive,
  2961. "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => $data.config.newTabOpenActive = $event)
  2962. }, null, 8, ["modelValue"])
  2963. ])
  2964. ])
  2965. ])) : vue.createCommentVNode("", true),
  2966. $data.tabIndex === 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_40$1, [
  2967. vue.createElementVNode("div", _hoisted_41$1, [
  2968. _hoisted_42$1,
  2969. vue.createElementVNode("div", _hoisted_43$1, [
  2970. vue.createVNode(_component_BaseSwitch, {
  2971. modelValue: $data.config.showToolbar,
  2972. "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => $data.config.showToolbar = $event)
  2973. }, null, 8, ["modelValue"])
  2974. ])
  2975. ]),
  2976. vue.createElementVNode("div", _hoisted_44$1, [
  2977. _hoisted_45$1,
  2978. vue.createElementVNode("div", _hoisted_46$1, [
  2979. vue.createVNode(_component_BaseSelect, {
  2980. "display-type": $data.config.commentDisplayType,
  2981. "onUpdate:displayType": _cache[12] || (_cache[12] = ($event) => $data.config.commentDisplayType = $event)
  2982. }, null, 8, ["display-type"])
  2983. ])
  2984. ]),
  2985. vue.createElementVNode("div", _hoisted_47$1, [
  2986. _hoisted_48$1,
  2987. vue.createElementVNode("div", _hoisted_49$1, [
  2988. vue.createVNode(_component_BaseSwitch, {
  2989. modelValue: $data.config.autoOpenDetail,
  2990. "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => $data.config.autoOpenDetail = $event)
  2991. }, null, 8, ["modelValue"])
  2992. ])
  2993. ]),
  2994. _hoisted_50,
  2995. vue.createElementVNode("div", _hoisted_51, [
  2996. _hoisted_52,
  2997. vue.createElementVNode("div", _hoisted_53, [
  2998. vue.createVNode(_component_BaseSwitch, {
  2999. modelValue: $data.config.closePostDetailBySpace,
  3000. "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.config.closePostDetailBySpace = $event)
  3001. }, null, 8, ["modelValue"])
  3002. ])
  3003. ]),
  3004. vue.createElementVNode("div", _hoisted_54, [
  3005. _hoisted_55,
  3006. vue.createElementVNode("div", _hoisted_56, [
  3007. vue.createVNode(_component_BaseSwitch, {
  3008. modelValue: $data.config.contentAutoCollapse,
  3009. "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => $data.config.contentAutoCollapse = $event)
  3010. }, null, 8, ["modelValue"])
  3011. ])
  3012. ]),
  3013. vue.createElementVNode("div", _hoisted_57, [
  3014. _hoisted_58,
  3015. vue.createElementVNode("div", _hoisted_59, [
  3016. vue.withDirectives(vue.createElementVNode("input", {
  3017. type: "text",
  3018. "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => $data.config.postWidth = $event)
  3019. }, null, 512), [
  3020. [vue.vModelText, $data.config.postWidth]
  3021. ])
  3022. ])
  3023. ]),
  3024. _hoisted_60,
  3025. _hoisted_61,
  3026. _hoisted_62,
  3027. _hoisted_63,
  3028. vue.createElementVNode("div", _hoisted_64, [
  3029. _hoisted_65,
  3030. vue.createElementVNode("div", _hoisted_66, [
  3031. vue.createVNode(_component_BaseSwitch, {
  3032. modelValue: $data.config.showTopReply,
  3033. "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => $data.config.showTopReply = $event)
  3034. }, null, 8, ["modelValue"])
  3035. ])
  3036. ]),
  3037. vue.createElementVNode("div", _hoisted_67, [
  3038. _hoisted_68,
  3039. vue.createElementVNode("div", _hoisted_69, [
  3040. vue.withDirectives(vue.createElementVNode("input", {
  3041. type: "number",
  3042. min: "1",
  3043. "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => $data.config.topReplyCount = $event)
  3044. }, null, 512), [
  3045. [vue.vModelText, $data.config.topReplyCount]
  3046. ])
  3047. ])
  3048. ]),
  3049. vue.createElementVNode("div", _hoisted_70, [
  3050. _hoisted_71,
  3051. vue.createElementVNode("div", _hoisted_72, [
  3052. vue.withDirectives(vue.createElementVNode("input", {
  3053. type: "number",
  3054. min: "1",
  3055. "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => $data.config.topReplyLoveMinCount = $event)
  3056. }, null, 512), [
  3057. [vue.vModelText, $data.config.topReplyLoveMinCount]
  3058. ])
  3059. ])
  3060. ])
  3061. ])) : vue.createCommentVNode("", true),
  3062. $data.tabIndex === 2 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_73, [
  3063. vue.createElementVNode("div", _hoisted_74, [
  3064. _hoisted_75,
  3065. vue.createElementVNode("div", _hoisted_76, [
  3066. vue.createVNode(_component_BaseSwitch, {
  3067. modelValue: $data.config.openTag,
  3068. "onUpdate:modelValue": _cache[20] || (_cache[20] = ($event) => $data.config.openTag = $event)
  3069. }, null, 8, ["modelValue"])
  3070. ])
  3071. ]),
  3072. _hoisted_77,
  3073. vue.createElementVNode("div", _hoisted_78, [
  3074. _hoisted_79,
  3075. vue.createElementVNode("div", _hoisted_80, [
  3076. vue.createVNode(_component_BaseSwitch, {
  3077. modelValue: $data.config.base64,
  3078. "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => $data.config.base64 = $event)
  3079. }, null, 8, ["modelValue"])
  3080. ])
  3081. ]),
  3082. vue.createElementVNode("div", _hoisted_81, [
  3083. _hoisted_82,
  3084. vue.createElementVNode("div", _hoisted_83, [
  3085. vue.createVNode(_component_BaseSwitch, {
  3086. modelValue: $data.config.autoSignin,
  3087. "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => $data.config.autoSignin = $event)
  3088. }, null, 8, ["modelValue"])
  3089. ])
  3090. ]),
  3091. vue.createElementVNode("div", _hoisted_84, [
  3092. _hoisted_85,
  3093. vue.createElementVNode("div", _hoisted_86, [
  3094. vue.withDirectives(vue.createElementVNode("input", {
  3095. type: "text",
  3096. "onUpdate:modelValue": _cache[23] || (_cache[23] = ($event) => $data.config.customBgColor = $event)
  3097. }, null, 512), [
  3098. [vue.vModelText, $data.config.customBgColor]
  3099. ])
  3100. ])
  3101. ]),
  3102. _hoisted_87,
  3103. _hoisted_88,
  3104. vue.createElementVNode("div", _hoisted_89, [
  3105. _hoisted_90,
  3106. vue.createElementVNode("div", _hoisted_91, [
  3107. vue.createVNode(_component_BaseSwitch, {
  3108. modelValue: $data.config.collectBrowserNotice,
  3109. "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => $data.config.collectBrowserNotice = $event)
  3110. }, null, 8, ["modelValue"])
  3111. ])
  3112. ]),
  3113. _hoisted_92
  3114. ])) : vue.createCommentVNode("", true),
  3115. $data.tabIndex === 3 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_93, [
  3116. _hoisted_94,
  3117. vue.createElementVNode("div", _hoisted_95, [
  3118. _hoisted_96,
  3119. _hoisted_97,
  3120. vue.createElementVNode("div", _hoisted_98, [
  3121. vue.createElementVNode("div", null, [
  3122. vue.createTextVNode("官网:"),
  3123. vue.createElementVNode("a", {
  3124. href: $options.DefaultVal.homeUrl,
  3125. target: "_blank"
  3126. }, vue.toDisplayString($options.DefaultVal.homeUrl), 9, _hoisted_99)
  3127. ]),
  3128. vue.createElementVNode("div", null, [
  3129. vue.createTextVNode("GitHub地址:"),
  3130. vue.createElementVNode("a", {
  3131. href: $options.DefaultVal.git,
  3132. target: "_blank"
  3133. }, vue.toDisplayString($options.DefaultVal.git), 9, _hoisted_100)
  3134. ]),
  3135. vue.createElementVNode("div", null, [
  3136. vue.createTextVNode("PC脚本地址:"),
  3137. vue.createElementVNode("a", {
  3138. href: $options.DefaultVal.pcScript,
  3139. target: "_blank"
  3140. }, vue.toDisplayString($options.DefaultVal.pcScript), 9, _hoisted_101)
  3141. ]),
  3142. vue.createElementVNode("div", null, [
  3143. vue.createTextVNode("移动端脚本地址:"),
  3144. vue.createElementVNode("a", {
  3145. href: $options.DefaultVal.mobileScript,
  3146. target: "_blank"
  3147. }, vue.toDisplayString($options.DefaultVal.mobileScript), 9, _hoisted_102)
  3148. ]),
  3149. vue.createElementVNode("div", null, [
  3150. vue.createTextVNode("反馈: "),
  3151. vue.createElementVNode("a", {
  3152. href: $options.DefaultVal.issue,
  3153. target: "_blank"
  3154. }, vue.toDisplayString($options.DefaultVal.issue), 9, _hoisted_103)
  3155. ]),
  3156. vue.createElementVNode("div", null, [
  3157. vue.createTextVNode("更新日志:"),
  3158. vue.createElementVNode("a", {
  3159. href: $options.DefaultVal.pcLog,
  3160. target: "_blank"
  3161. }, vue.toDisplayString($options.DefaultVal.pcLog), 9, _hoisted_104)
  3162. ])
  3163. ])
  3164. ])
  3165. ])) : vue.createCommentVNode("", true)
  3166. ])
  3167. ])
  3168. ])
  3169. ]),
  3170. vue.createVNode(_component_NoticeModal, {
  3171. show: $data.showNotice,
  3172. "onUpdate:show": _cache[25] || (_cache[25] = ($event) => $data.showNotice = $event),
  3173. onConfirm: _cache[26] || (_cache[26] = ($event) => $data.config.viewType = "card")
  3174. }, null, 8, ["show"])
  3175. ])) : vue.createCommentVNode("", true)
  3176. ]),
  3177. _: 1
  3178. });
  3179. }
  3180. const Setting = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$7], ["__scopeId", "data-v-df0e0e8f"]]);
  3181. const eventBus = {
  3182. eventMap: /* @__PURE__ */ new Map(),
  3183. on(eventType, cb) {
  3184. let cbs = this.eventMap.get(eventType);
  3185. if (cbs) {
  3186. cbs.push(cb);
  3187. } else {
  3188. cbs = [cb];
  3189. }
  3190. this.eventMap.set(eventType, cbs);
  3191. },
  3192. emit(eventType, val) {
  3193. let cbs = this.eventMap.get(eventType);
  3194. if (cbs) {
  3195. cbs.map((cb) => cb(val));
  3196. }
  3197. },
  3198. off(eventType) {
  3199. let cbs = this.eventMap.has(eventType);
  3200. if (cbs) {
  3201. this.eventMap.delete(eventType);
  3202. }
  3203. },
  3204. clear() {
  3205. this.eventMap = /* @__PURE__ */ new Map();
  3206. }
  3207. };
  3208. const CMD = {
  3209. SHOW_TOOLTIP: "SHOW_TOOLTIP",
  3210. SHOW_MSG: "SHOW_MSG",
  3211. SET_CALL: "SET_CALL",
  3212. SHOW_CALL: "SHOW_CALL",
  3213. REFRESH_ONCE: "REFRESH_ONCE",
  3214. ADD_REPLY: "ADD_REPLY",
  3215. IGNORE: "IGNORE",
  3216. MERGE: "MERGE",
  3217. REMOVE: "REMOVE",
  3218. CHANGE_COMMENT_THANK: "CHANGE_COMMENT_THANK",
  3219. CHANGE_POST_THANK: "CHANGE_POST_THANK",
  3220. ADD_TAG: "ADD_TAG",
  3221. REMOVE_TAG: "REMOVE_TAG",
  3222. RELATION_REPLY: "RELATION_REPLY",
  3223. JUMP: "JUMP",
  3224. REFRESH_POST: "REFRESH_POST"
  3225. };
  3226. const _sfc_main$d = {
  3227. name: "Point",
  3228. components: { PopConfirm, Icon },
  3229. inject: ["post", "isLogin"],
  3230. props: {
  3231. item: {
  3232. type: Object,
  3233. default() {
  3234. return {};
  3235. }
  3236. },
  3237. apiUrl: ""
  3238. },
  3239. computed: {
  3240. disabled() {
  3241. return this.item.username === window.user.username || this.item.isThanked || !this.isLogin;
  3242. }
  3243. },
  3244. methods: {
  3245. thankError() {
  3246. if (!this.isLogin) {
  3247. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  3248. }
  3249. if (this.item.username === window.user.username) {
  3250. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "不能感谢自己" });
  3251. }
  3252. if (this.item.isThanked) {
  3253. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "已经感谢过了" });
  3254. }
  3255. },
  3256. async thank() {
  3257. this.$emit("addThank");
  3258. let url = `${window.baseUrl}/thank/${this.apiUrl}?once=${this.post.once}`;
  3259. $.post(url).then((res) => {
  3260. if (!res.success) {
  3261. this.$emit("recallThank");
  3262. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: res.message });
  3263. }
  3264. eventBus.emit(CMD.REFRESH_ONCE, res.once);
  3265. }, (err) => {
  3266. this.$emit("recallThank");
  3267. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "感谢失败" });
  3268. eventBus.emit(CMD.REFRESH_ONCE);
  3269. });
  3270. }
  3271. }
  3272. };
  3273. const _hoisted_1$d = {
  3274. key: 2,
  3275. class: "link-num"
  3276. };
  3277. const _hoisted_2$a = { key: 3 };
  3278. function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
  3279. const _component_Icon = vue.resolveComponent("Icon");
  3280. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  3281. return vue.openBlock(), vue.createBlock(_component_PopConfirm, {
  3282. disabled: $options.disabled,
  3283. title: `确认花费 10 个铜币向 @${$props.item.username} 的这条回复发送感谢?`,
  3284. onConfirm: $options.thank
  3285. }, {
  3286. default: vue.withCtx(() => [
  3287. vue.createElementVNode("div", {
  3288. class: vue.normalizeClass(["tool", [$options.disabled && "disabled"]]),
  3289. onClick: _cache[0] || (_cache[0] = (...args) => $options.thankError && $options.thankError(...args))
  3290. }, [
  3291. $props.item.isThanked ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  3292. key: 0,
  3293. color: "rgb(224,42,42)",
  3294. icon: "icon-park-solid:like"
  3295. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  3296. key: 1,
  3297. color: !$props.item.thankCount ? null : "rgb(224,42,42)",
  3298. icon: "icon-park-outline:like"
  3299. }, null, 8, ["color"])),
  3300. $props.item.thankCount ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_1$d, vue.toDisplayString($props.item.thankCount), 1)) : (vue.openBlock(), vue.createElementBlock("span", _hoisted_2$a, "感谢"))
  3301. ], 2)
  3302. ]),
  3303. _: 1
  3304. }, 8, ["disabled", "title", "onConfirm"]);
  3305. }
  3306. const Point = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$6]]);
  3307. const _sfc_main$c = {
  3308. name: "Author",
  3309. components: { PopConfirm, Point, Icon },
  3310. inject: ["isLogin", "tags", "config", "isNight"],
  3311. props: {
  3312. modelValue: false,
  3313. comment: {
  3314. type: Object,
  3315. default() {
  3316. return {};
  3317. }
  3318. },
  3319. type: {
  3320. type: String,
  3321. default() {
  3322. return "list";
  3323. }
  3324. }
  3325. },
  3326. computed: {
  3327. isDev() {
  3328. return false;
  3329. },
  3330. pointInfo() {
  3331. return {
  3332. isThanked: this.comment.isThanked,
  3333. thankCount: this.comment.thankCount,
  3334. username: this.comment.username
  3335. };
  3336. },
  3337. myTags() {
  3338. return this.tags[this.comment.username] ?? [];
  3339. },
  3340. context() {
  3341. return this.comment.replyUsers.length;
  3342. }
  3343. },
  3344. methods: {
  3345. jump() {
  3346. eventBus.emit(CMD.JUMP, this.comment.floor);
  3347. },
  3348. showRelationReply() {
  3349. if (!this.comment.replyUsers.length) {
  3350. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "该回复无上下文" });
  3351. return;
  3352. }
  3353. eventBus.emit(CMD.RELATION_REPLY, {
  3354. left: this.comment.replyUsers,
  3355. right: this.comment.username,
  3356. rightFloor: this.comment.floor
  3357. });
  3358. },
  3359. addTag() {
  3360. eventBus.emit(CMD.ADD_TAG, this.comment.username);
  3361. },
  3362. removeTag(tag) {
  3363. eventBus.emit(CMD.REMOVE_TAG, { username: this.comment.username, tag });
  3364. },
  3365. checkIsLogin(emitName = "") {
  3366. if (!this.isLogin) {
  3367. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  3368. return false;
  3369. }
  3370. this.$emit(emitName);
  3371. return true;
  3372. },
  3373. addThank() {
  3374. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "add" });
  3375. },
  3376. recallThank() {
  3377. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "recall" });
  3378. }
  3379. }
  3380. };
  3381. const _withScopeId$8 = (n2) => (vue.pushScopeId("data-v-53261a54"), n2 = n2(), vue.popScopeId(), n2);
  3382. const _hoisted_1$c = { class: "Author-left" };
  3383. const _hoisted_2$9 = ["href"];
  3384. const _hoisted_3$8 = ["src"];
  3385. const _hoisted_4$8 = { class: "texts" };
  3386. const _hoisted_5$6 = ["href"];
  3387. const _hoisted_6$6 = {
  3388. key: 0,
  3389. class: "owner"
  3390. };
  3391. const _hoisted_7$5 = {
  3392. key: 1,
  3393. class: "dup"
  3394. };
  3395. const _hoisted_8$5 = {
  3396. key: 2,
  3397. class: "mod"
  3398. };
  3399. const _hoisted_9$5 = { class: "ago" };
  3400. const _hoisted_10$4 = { class: "my-tag" };
  3401. const _hoisted_11$4 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  3402. const _hoisted_12$4 = ["onClick"];
  3403. const _hoisted_13$4 = { class: "Author-right" };
  3404. const _hoisted_14$4 = {
  3405. key: 0,
  3406. class: "toolbar"
  3407. };
  3408. const _hoisted_15$3 = { class: "tool" };
  3409. const _hoisted_16$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "隐藏", -1));
  3410. const _hoisted_17$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上下文", -1));
  3411. const _hoisted_18$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  3412. const _hoisted_19$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复", -1));
  3413. function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
  3414. const _component_Icon = vue.resolveComponent("Icon");
  3415. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  3416. const _component_Point = vue.resolveComponent("Point");
  3417. return vue.openBlock(), vue.createElementBlock("div", {
  3418. class: vue.normalizeClass(["Author", { expand: !$props.modelValue }])
  3419. }, [
  3420. vue.createElementVNode("div", _hoisted_1$c, [
  3421. !$props.modelValue ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  3422. key: 0,
  3423. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", true)),
  3424. color: "#177EC9",
  3425. class: "expand-icon",
  3426. icon: "gravity-ui:chevrons-expand-up-right"
  3427. })) : vue.createCommentVNode("", true),
  3428. $options.config.viewType !== "simple" ? (vue.openBlock(), vue.createElementBlock("a", {
  3429. key: 1,
  3430. class: "avatar",
  3431. href: `/member/${$props.comment.username}`
  3432. }, [
  3433. vue.createElementVNode("img", {
  3434. src: $props.comment.avatar,
  3435. alt: ""
  3436. }, null, 8, _hoisted_3$8)
  3437. ], 8, _hoisted_2$9)) : vue.createCommentVNode("", true),
  3438. vue.createElementVNode("span", _hoisted_4$8, [
  3439. vue.createElementVNode("strong", null, [
  3440. vue.createElementVNode("a", {
  3441. href: `/member/${$props.comment.username}`,
  3442. class: vue.normalizeClass(["username", { "dark": $options.isNight }])
  3443. }, vue.toDisplayString($props.comment.username), 11, _hoisted_5$6)
  3444. ]),
  3445. $props.comment.isOp ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6$6, "OP")) : vue.createCommentVNode("", true),
  3446. $props.comment.isDup ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7$5, "DUP")) : vue.createCommentVNode("", true),
  3447. $props.comment.isMod ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8$5, "MOD")) : vue.createCommentVNode("", true),
  3448. vue.createElementVNode("span", _hoisted_9$5, vue.toDisplayString($props.comment.date), 1),
  3449. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 3 }, [
  3450. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  3451. return vue.openBlock(), vue.createElementBlock("span", _hoisted_10$4, [
  3452. _hoisted_11$4,
  3453. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  3454. vue.createElementVNode("i", {
  3455. class: "fa fa-trash-o remove",
  3456. onClick: ($event) => $options.removeTag(i)
  3457. }, null, 8, _hoisted_12$4)
  3458. ]);
  3459. }), 256)),
  3460. vue.createElementVNode("span", {
  3461. class: "add-tag ago",
  3462. onClick: _cache[1] || (_cache[1] = (...args) => $options.addTag && $options.addTag(...args)),
  3463. title: "添加标签"
  3464. }, "+")
  3465. ], 64)) : vue.createCommentVNode("", true)
  3466. ])
  3467. ]),
  3468. vue.createElementVNode("div", _hoisted_13$4, [
  3469. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$4, [
  3470. vue.createVNode(_component_PopConfirm, {
  3471. title: "确认隐藏这条回复?",
  3472. onConfirm: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("hide"))
  3473. }, {
  3474. default: vue.withCtx(() => [
  3475. vue.createElementVNode("div", _hoisted_15$3, [
  3476. vue.createVNode(_component_Icon, { icon: "fluent:eye-hide-24-regular" }),
  3477. _hoisted_16$3
  3478. ])
  3479. ]),
  3480. _: 1
  3481. }),
  3482. $options.context ? (vue.openBlock(), vue.createElementBlock("div", {
  3483. key: 0,
  3484. class: "tool",
  3485. onClick: _cache[3] || (_cache[3] = (...args) => $options.showRelationReply && $options.showRelationReply(...args))
  3486. }, [
  3487. vue.createVNode(_component_Icon, { icon: "iconoir:page-search" }),
  3488. _hoisted_17$2
  3489. ])) : vue.createCommentVNode("", true),
  3490. $props.type === "top" ? (vue.openBlock(), vue.createElementBlock("div", {
  3491. key: 1,
  3492. class: "tool",
  3493. onClick: _cache[4] || (_cache[4] = (...args) => $options.jump && $options.jump(...args))
  3494. }, [
  3495. vue.createVNode(_component_Icon, { icon: "icon-park-outline:to-bottom" }),
  3496. _hoisted_18$2
  3497. ])) : vue.createCommentVNode("", true),
  3498. vue.createElementVNode("div", {
  3499. class: "tool",
  3500. onClick: _cache[5] || (_cache[5] = ($event) => $options.checkIsLogin("reply"))
  3501. }, [
  3502. vue.createVNode(_component_Icon, { icon: "mynaui:message" }),
  3503. _hoisted_19$2
  3504. ]),
  3505. vue.withDirectives(vue.createVNode(_component_Point, {
  3506. item: $options.pointInfo,
  3507. onAddThank: $options.addThank,
  3508. onRecallThank: $options.recallThank,
  3509. "api-url": "reply/" + $props.comment.id
  3510. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  3511. [vue.vShow, !$props.comment.thankCount]
  3512. ])
  3513. ])) : vue.createCommentVNode("", true),
  3514. vue.withDirectives(vue.createVNode(_component_Point, {
  3515. item: $options.pointInfo,
  3516. onAddThank: $options.addThank,
  3517. onRecallThank: $options.recallThank,
  3518. "api-url": "reply/" + $props.comment.id
  3519. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  3520. [vue.vShow, $props.comment.thankCount]
  3521. ]),
  3522. vue.createElementVNode("div", {
  3523. class: vue.normalizeClass(["floor", { isDev: $options.isDev }])
  3524. }, vue.toDisplayString($props.comment.floor), 3)
  3525. ])
  3526. ], 2);
  3527. }
  3528. const Author = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["render", _sfc_render$5], ["__scopeId", "data-v-53261a54"]]);
  3529. const _withScopeId$7 = (n2) => (vue.pushScopeId("data-v-4522f98e"), n2 = n2(), vue.popScopeId(), n2);
  3530. const _hoisted_1$b = { class: "get-cursor" };
  3531. const _hoisted_2$8 = ["innerHTML"];
  3532. const _hoisted_3$7 = { class: "toolbar" };
  3533. const _hoisted_4$7 = { class: "left" };
  3534. const _hoisted_5$5 = { class: "upload" };
  3535. const _hoisted_6$5 = {
  3536. key: 0,
  3537. style: { "color": "black", "font-size": "1.4rem" }
  3538. };
  3539. const _hoisted_7$4 = { class: "right" };
  3540. const _hoisted_8$4 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, "经典表情", -1));
  3541. const _hoisted_9$4 = { class: "list" };
  3542. const _hoisted_10$3 = ["src", "onClick"];
  3543. const _hoisted_11$3 = { class: "emoji" };
  3544. const _hoisted_12$3 = { class: "title" };
  3545. const _hoisted_13$3 = { class: "list" };
  3546. const _hoisted_14$3 = ["onClick"];
  3547. const _sfc_main$b = {
  3548. __name: "PostEditor",
  3549. props: {
  3550. replyUser: null,
  3551. replyFloor: null,
  3552. useType: {
  3553. type: String,
  3554. default() {
  3555. return "reply-comment";
  3556. }
  3557. }
  3558. },
  3559. emits: ["close"],
  3560. setup(__props, { expose: __expose, emit: __emit }) {
  3561. const props = __props;
  3562. const { replyUser, replyFloor, useType } = props;
  3563. const replyInfo = replyUser ? `@${replyUser} #${replyFloor} ` : "";
  3564. const emits = __emit;
  3565. const post = vue.inject("post");
  3566. const show = vue.inject("show");
  3567. const isNight = vue.inject("isNight");
  3568. vue.inject("pageType");
  3569. const allReplyUsers = vue.inject("allReplyUsers");
  3570. let isFocus = vue.ref(false);
  3571. const loading = vue.ref(false);
  3572. const uploadLoading = vue.ref(false);
  3573. const isShowEmoticons = vue.ref(false);
  3574. const editorId = vue.ref("editorId_" + Date.now());
  3575. const content = vue.ref(replyInfo);
  3576. const txtRef = vue.ref(null);
  3577. const cursorRef = vue.ref(null);
  3578. const emoticonsRef = vue.ref(null);
  3579. const none = vue.ref('<span style="white-space:pre-wrap;"> </span>');
  3580. const emojiEmoticons = [
  3581. {
  3582. title: "小黄脸",
  3583. list: [
  3584. "😀",
  3585. "😁",
  3586. "😂",
  3587. "🤣",
  3588. "😅",
  3589. "😊",
  3590. "😋",
  3591. "😘",
  3592. "🥰",
  3593. "😗",
  3594. "🤩",
  3595. "🤔",
  3596. "🤨",
  3597. "😐",
  3598. "😑",
  3599. "🙄",
  3600. "😏",
  3601. "😪",
  3602. "😫",
  3603. "🥱",
  3604. "😜",
  3605. "😒",
  3606. "😔",
  3607. "😨",
  3608. "😰",
  3609. "😱",
  3610. "🥵",
  3611. "😡",
  3612. "🥳",
  3613. "🥺",
  3614. "🤭",
  3615. "🧐",
  3616. "😎",
  3617. "🤓",
  3618. "😭",
  3619. "🤑",
  3620. "🤮"
  3621. ]
  3622. },
  3623. {
  3624. title: "手势",
  3625. list: [
  3626. "🙋",
  3627. "🙎",
  3628. "🙅",
  3629. "🙇",
  3630. "🤷",
  3631. "🤏",
  3632. "👉",
  3633. "✌️",
  3634. "🤘",
  3635. "🤙",
  3636. "👌",
  3637. "🤌",
  3638. "👍",
  3639. "👎",
  3640. "👋",
  3641. "🤝",
  3642. "🙏",
  3643. "👏"
  3644. ]
  3645. },
  3646. {
  3647. title: "庆祝",
  3648. list: ["✨", "🎉", "🎊"]
  3649. },
  3650. {
  3651. title: "其他",
  3652. list: ["👻", "🤡", "🐔", "👀", "💩", "🐴", "🦄", "🐧", "🐶", "🐒", "🙈", "🙉", "🙊", "🐵"]
  3653. }
  3654. ];
  3655. const classicsEmoticons = [
  3656. {
  3657. name: "[狗头]",
  3658. low: "https://i.imgur.com/io2SM1h.png",
  3659. high: "https://i.imgur.com/0icl60r.png"
  3660. },
  3661. {
  3662. name: "[马]",
  3663. low: "https://i.imgur.com/8EKZv7I.png",
  3664. high: "https://i.imgur.com/ANFUX52.png"
  3665. },
  3666. {
  3667. name: "[不高兴]",
  3668. low: "https://i.imgur.com/huX6coX.png",
  3669. high: "https://i.imgur.com/N7JEuvc.png"
  3670. },
  3671. {
  3672. name: "[呵呵]",
  3673. low: "https://i.imgur.com/RvoLAbX.png",
  3674. high: "https://i.imgur.com/xSzIqrK.png"
  3675. },
  3676. {
  3677. name: "[真棒]",
  3678. low: "https://i.imgur.com/xr1UOz1.png",
  3679. high: "https://i.imgur.com/w8YEw9Q.png"
  3680. },
  3681. {
  3682. name: "[鄙视]",
  3683. low: "https://i.imgur.com/u6jlqVq.png",
  3684. high: "https://i.imgur.com/8JFNANq.png"
  3685. },
  3686. {
  3687. name: "[疑问]",
  3688. low: "https://i.imgur.com/F29pmQ6.png",
  3689. high: "https://i.imgur.com/EbbTQAR.png"
  3690. },
  3691. {
  3692. name: "[吐舌]",
  3693. low: "https://i.imgur.com/InmIzl9.png",
  3694. high: "https://i.imgur.com/Ovj56Cd.png"
  3695. },
  3696. // {
  3697. // name: '[嘲笑]',
  3698. // low: 'https://i.imgur.com/BaWcsMR.png',
  3699. // high: 'https://i.imgur.com/0OGfJw4.png'
  3700. // },
  3701. // {
  3702. // name: '[滑稽]',
  3703. // low: 'https://i.imgur.com/lmbN0yI.png',
  3704. // high: 'https://i.imgur.com/Pc0wH85.png'
  3705. // },
  3706. {
  3707. name: "[笑眼]",
  3708. low: "https://i.imgur.com/ZveiiGy.png",
  3709. high: "https://i.imgur.com/PI1CfEr.png"
  3710. },
  3711. {
  3712. name: "[狂汗]",
  3713. low: "https://i.imgur.com/veWihk6.png",
  3714. high: "https://i.imgur.com/3LtHdQv.png"
  3715. },
  3716. {
  3717. name: "[大哭]",
  3718. low: "https://i.imgur.com/hu4oR6C.png",
  3719. high: "https://i.imgur.com/b4X9XLE.png"
  3720. },
  3721. {
  3722. name: "[喷]",
  3723. low: "https://i.imgur.com/bkw3VRr.png",
  3724. high: "https://i.imgur.com/wnZL13L.png"
  3725. },
  3726. {
  3727. name: "[苦笑]",
  3728. low: "https://i.imgur.com/VUWFktU.png",
  3729. high: "https://i.imgur.com/NAfspZ1.png"
  3730. },
  3731. {
  3732. name: "[喝酒]",
  3733. low: "https://i.imgur.com/2ZZSapE.png",
  3734. high: "https://i.imgur.com/rVbSVak.png"
  3735. },
  3736. {
  3737. name: "[吃瓜]",
  3738. low: "https://i.imgur.com/ee8Lq7H.png",
  3739. high: "https://i.imgur.com/0L26og9.png"
  3740. },
  3741. {
  3742. name: "[捂脸]",
  3743. low: "https://i.imgur.com/krir4IG.png",
  3744. high: "https://i.imgur.com/qqBqgVm.png"
  3745. },
  3746. {
  3747. name: "[呕]",
  3748. low: "https://i.imgur.com/6CUiUxv.png",
  3749. high: "https://i.imgur.com/kgdxRsG.png"
  3750. },
  3751. {
  3752. name: "[阴险]",
  3753. low: "https://i.imgur.com/MA8YqTP.png",
  3754. high: "https://i.imgur.com/e94jbaT.png"
  3755. },
  3756. {
  3757. name: "[怒]",
  3758. low: "https://i.imgur.com/n4kWfGB.png",
  3759. high: "https://i.imgur.com/iMXxNxh.png"
  3760. },
  3761. {
  3762. name: "[衰]",
  3763. low: "https://i.imgur.com/voHFDyQ.png",
  3764. high: "https://i.imgur.com/XffE6gu.png"
  3765. },
  3766. {
  3767. name: "[合十]",
  3768. low: "https://i.imgur.com/I8x3ang.png",
  3769. high: "https://i.imgur.com/T4rJVee.png"
  3770. },
  3771. {
  3772. name: "[赞]",
  3773. low: "https://i.imgur.com/lG44yUl.png",
  3774. high: "https://i.imgur.com/AoF5PLp.png"
  3775. },
  3776. {
  3777. name: "[踩]",
  3778. low: "https://i.imgur.com/cJp0uKZ.png",
  3779. high: "https://i.imgur.com/1XYGfXj.png"
  3780. },
  3781. {
  3782. name: "[爱心]",
  3783. low: "https://i.imgur.com/sLENaF5.png",
  3784. high: "https://i.imgur.com/dND56oX.png"
  3785. },
  3786. {
  3787. name: "[心碎]",
  3788. low: "https://i.imgur.com/AZxJzve.png",
  3789. high: "https://i.imgur.com/RiUsPci.png"
  3790. }
  3791. ];
  3792. const imgurClientIdPool = [
  3793. "3107b9ef8b316f3",
  3794. "442b04f26eefc8a",
  3795. "59cfebe717c09e4",
  3796. "60605aad4a62882",
  3797. "6c65ab1d3f5452a",
  3798. "83e123737849aa9",
  3799. "9311f6be1c10160",
  3800. "c4a4a563f698595",
  3801. "81be04b9e4a08ce"
  3802. ];
  3803. __expose({ content, isFocus: () => isFocus.value });
  3804. const editorClass = vue.computed(() => {
  3805. return [useType, isFocus.value ? "isFocus" : "", isNight.value ? "isNight" : ""];
  3806. });
  3807. const cursorHtml = vue.computed(() => {
  3808. var _a;
  3809. if (!txtRef.value || !content.value)
  3810. return "";
  3811. let index = ((_a = txtRef.value) == null ? void 0 : _a.selectionStart) || 0;
  3812. return content.value.substring(0, index).replace(/</g, "<").replace(/>/g, ">").replace(/\n/g, "<br/>").replace(/\s/g, none.value);
  3813. });
  3814. const disabled = vue.computed(() => {
  3815. if (content.value) {
  3816. return content.value === replyInfo;
  3817. } else {
  3818. return true;
  3819. }
  3820. });
  3821. function drop(e2) {
  3822. e2.preventDefault();
  3823. upload(e2.dataTransfer.files[0]);
  3824. }
  3825. async function upload(file) {
  3826. if (!file)
  3827. return;
  3828. if (uploadLoading.value)
  3829. return;
  3830. uploadLoading.value = true;
  3831. const formData = new FormData();
  3832. formData.append("image", file);
  3833. const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
  3834. const clidenId = imgurClientIdPool[randomIndex];
  3835. const res = await fetch("https://api.imgur.com/3/upload", {
  3836. method: "POST",
  3837. headers: { Authorization: `Client-ID ${clidenId}` },
  3838. body: formData
  3839. });
  3840. uploadLoading.value = false;
  3841. if (res.ok) {
  3842. const resData = await res.json();
  3843. if (resData.success) {
  3844. return insert(" " + resData.data.link + " ");
  3845. }
  3846. }
  3847. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "上传失败" });
  3848. }
  3849. async function submit() {
  3850. if (disabled.value || loading.value)
  3851. return;
  3852. loading.value = true;
  3853. let submit_content = content.value.replace(/\[((?!\[).)+\]/g, function(match) {
  3854. let item2 = classicsEmoticons.find((v) => v.name === match);
  3855. if (item2) {
  3856. return item2.low + " ";
  3857. }
  3858. return match;
  3859. });
  3860. let show_content = content.value.replace(/https?:\/\/(i\.)?imgur\.com\/((?!http).)+\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)/g, function(match) {
  3861. return `<img src="${match}" data-originUrl="${match}" data-notice="这个img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`;
  3862. });
  3863. show_content = show_content.replace(/\[((?!\[).)+\]/g, function(match) {
  3864. let item2 = classicsEmoticons.find((v) => v.name === match);
  3865. if (item2) {
  3866. return `<a target="_blank" href="${item2.low}" rel="nofollow noopener"><img src="${item2.low}" class="embedded_image" rel="noreferrer"></a> `;
  3867. }
  3868. return match;
  3869. });
  3870. let matchUsers = show_content.match(/@([\w]+?[\s])/g);
  3871. if (matchUsers) {
  3872. matchUsers.map((i) => {
  3873. let username = i.replace("@", "").replace(" ", "");
  3874. show_content = show_content.replace(username, `<a href="/member/${username}">${username}</a>`);
  3875. });
  3876. }
  3877. show_content = show_content.replaceAll("\n", "<br/>");
  3878. let item = {
  3879. thankCount: 0,
  3880. isThanked: false,
  3881. isOp: post.value.username === window.user.username,
  3882. isDup: false,
  3883. id: Date.now(),
  3884. username: window.user.username,
  3885. avatar: window.user.avatar,
  3886. date: "几秒前",
  3887. floor: post.value.replyCount + 1,
  3888. reply_content: show_content ?? "",
  3889. children: [],
  3890. replyUsers: replyUser ? [replyUser] : [],
  3891. replyFloor: replyFloor || -1,
  3892. level: useType === "reply-comment" ? 1 : 0
  3893. };
  3894. item.hideCallUserReplyContent = item.reply_content;
  3895. if (item.replyUsers.length === 1) {
  3896. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(\s#[\d]+)?\s(<br>)?/, () => "");
  3897. }
  3898. console.log("回复", item);
  3899. let url = `${window.baseUrl}/t/${post.value.id}`;
  3900. $.post(url, { content: submit_content, once: post.value.once }).then(
  3901. // $.post(url, {content: submit_content, once: 123}).then(
  3902. (res) => {
  3903. loading.value = false;
  3904. let r2 = res.search("你上一条回复的内容和这条相同");
  3905. if (r2 > -1)
  3906. return eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你上一条回复的内容和这条相同" });
  3907. r2 = res.search("请不要在每一个回复中都包括外链,这看起来像是在 spamming");
  3908. if (r2 > -1)
  3909. return eventBus.emit(CMD.SHOW_MSG, {
  3910. type: "error",
  3911. text: "请不要在每一个回复中都包括外链,这看起来像是在 spamming"
  3912. });
  3913. let r22 = res.search("创建新回复");
  3914. if (r22 > -1) {
  3915. eventBus.emit(CMD.REFRESH_ONCE, res);
  3916. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复出现了问题,请使用原版进行回复" });
  3917. let clientWidth = window.document.body.clientWidth;
  3918. let windowWidth = 1200;
  3919. let left = clientWidth / 2 - windowWidth / 2;
  3920. let newWin = window.open("创建新回复", "", `width=${windowWidth},height=600,left=${left},top=100`);
  3921. newWin.document.write(res);
  3922. let loop = setInterval(function() {
  3923. if (newWin.closed) {
  3924. clearInterval(loop);
  3925. eventBus.emit(CMD.REFRESH_POST);
  3926. }
  3927. }, 1e3);
  3928. return;
  3929. }
  3930. content.value = replyInfo;
  3931. emits("close");
  3932. eventBus.emit(CMD.REFRESH_ONCE, res);
  3933. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "回复成功" });
  3934. eventBus.emit(CMD.ADD_REPLY, item);
  3935. },
  3936. (err) => {
  3937. console.log("err", err);
  3938. loading.value = false;
  3939. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
  3940. }
  3941. ).catch((r2) => {
  3942. console.log("catch", r2);
  3943. });
  3944. }
  3945. function showEmoticons(e2) {
  3946. if (isShowEmoticons.value) {
  3947. return isShowEmoticons.value = false;
  3948. }
  3949. let rect = e2.currentTarget.getBoundingClientRect();
  3950. emoticonsRef.value.style.left = rect.left + 30 + "px";
  3951. emoticonsRef.value.style.bottom = window.innerHeight - rect.top - 20 + "px";
  3952. isShowEmoticons.value = true;
  3953. }
  3954. function off() {
  3955. eventBus.emit(CMD.SHOW_CALL, { show: false });
  3956. eventBus.off(CMD.SET_CALL);
  3957. }
  3958. function checkHeight2() {
  3959. txtRef.value.style.height = 0;
  3960. txtRef.value.style.height = txtRef.value.scrollHeight + "px";
  3961. }
  3962. function insert(str) {
  3963. let cursorPos = txtRef.value.selectionStart;
  3964. let start = content.value.slice(0, cursorPos);
  3965. let end = content.value.slice(cursorPos, content.value.length);
  3966. content.value = start + str + end;
  3967. let moveCursorPos = start.length + str.length;
  3968. setTimeout(() => {
  3969. txtRef.value.focus();
  3970. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  3971. checkHeight2();
  3972. });
  3973. }
  3974. function showCallPopover(text) {
  3975. let r2 = cursorRef.value.getBoundingClientRect();
  3976. eventBus.emit(CMD.SHOW_CALL, { show: true, top: r2.top, left: r2.left, text });
  3977. eventBus.off(CMD.SET_CALL);
  3978. eventBus.on(CMD.SET_CALL, (e2) => {
  3979. let cursorPos = txtRef.value.selectionStart;
  3980. let start = content.value.slice(0, cursorPos);
  3981. let end = content.value.slice(cursorPos, content.value.length);
  3982. let lastCallPos = start.lastIndexOf("@");
  3983. start = content.value.slice(0, lastCallPos + 1);
  3984. if (e2 === "管理员") {
  3985. e2 = "Livid @Kai @Olivia @GordianZ @sparanoid";
  3986. }
  3987. if (e2 === "所有人") {
  3988. e2 = allReplyUsers.value.map((v, i) => {
  3989. if (i)
  3990. return "@" + v;
  3991. else
  3992. return v;
  3993. }).join(" ");
  3994. }
  3995. content.value = start + e2 + " " + end;
  3996. let moveCursorPos = start.length + e2.length + 1;
  3997. setTimeout(() => {
  3998. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  3999. checkHeight2();
  4000. });
  4001. eventBus.off(CMD.SET_CALL);
  4002. });
  4003. }
  4004. function onKeydown(e2) {
  4005. let code = e2.keyCode;
  4006. switch (code) {
  4007. case 8:
  4008. if (content.value === "@") {
  4009. off();
  4010. }
  4011. break;
  4012. case 37:
  4013. case 38:
  4014. case 39:
  4015. case 40:
  4016. setTimeout(() => onInput({ data: "" }), 100);
  4017. break;
  4018. case 27:
  4019. e2.preventDefault();
  4020. e2.stopPropagation();
  4021. e2.stopImmediatePropagation();
  4022. return false;
  4023. case 13:
  4024. if (e2.ctrlKey)
  4025. submit();
  4026. if (e2.metaKey)
  4027. submit();
  4028. break;
  4029. }
  4030. }
  4031. function onInput(e2) {
  4032. let cursorPos = txtRef.value.selectionStart;
  4033. if (!content.value)
  4034. return;
  4035. if (e2.data === " ") {
  4036. return off();
  4037. }
  4038. if (e2.data === "@") {
  4039. if (content.value.length !== 1) {
  4040. if (content.value[cursorPos - 2] === " " || content.value[cursorPos - 2] === "\n") {
  4041. return showCallPopover("");
  4042. }
  4043. } else {
  4044. return showCallPopover("");
  4045. }
  4046. off();
  4047. } else {
  4048. let judgeStr = content.value.slice(0, cursorPos);
  4049. let lastCallPos = judgeStr.lastIndexOf("@");
  4050. if (lastCallPos === -1) {
  4051. return off();
  4052. }
  4053. let callStr = judgeStr.slice(lastCallPos, cursorPos);
  4054. let hasSpace = callStr.includes(" ");
  4055. if (hasSpace) {
  4056. off();
  4057. } else {
  4058. if (lastCallPos === 0) {
  4059. return showCallPopover(callStr.replace("@", ""));
  4060. }
  4061. if (content.value.length !== 1) {
  4062. if (content.value[lastCallPos - 1] === " " || content.value[lastCallPos - 1] === "\n") {
  4063. return showCallPopover(callStr.replace("@", ""));
  4064. }
  4065. } else {
  4066. return showCallPopover(callStr.replace("@", ""));
  4067. }
  4068. off();
  4069. }
  4070. }
  4071. }
  4072. function onPaste(e2) {
  4073. const dataTransferItemList = e2.clipboardData.items;
  4074. const items = [].slice.call(dataTransferItemList).filter(function(item) {
  4075. return item.type.indexOf("image") !== -1;
  4076. });
  4077. if (items.length === 0) {
  4078. return;
  4079. }
  4080. const dataTransferItem = items[0];
  4081. const blob = dataTransferItem.getAsFile();
  4082. upload(blob);
  4083. }
  4084. function onBlur() {
  4085. document.removeEventListener("paste", onPaste);
  4086. isFocus.value = false;
  4087. }
  4088. function onFocusin() {
  4089. document.addEventListener("paste", onPaste);
  4090. }
  4091. vue.watch(() => show, (n2) => {
  4092. if (n2.value)
  4093. isShowEmoticons.value = false;
  4094. }, { deep: true });
  4095. vue.onMounted(() => {
  4096. $(`.${editorId.value}`).each(function() {
  4097. this.setAttribute("style", "height:" + this.scrollHeight + "px;overflow-y:hidden;");
  4098. }).on("input", function() {
  4099. this.style.height = 0;
  4100. this.style.height = this.scrollHeight + "px";
  4101. });
  4102. if (useType === "reply-comment") {
  4103. txtRef.value && txtRef.value.focus();
  4104. }
  4105. });
  4106. vue.onBeforeUnmount(() => {
  4107. $(`.${editorId.value}`).off();
  4108. });
  4109. return (_ctx, _cache) => {
  4110. return vue.openBlock(), vue.createElementBlock("div", {
  4111. class: vue.normalizeClass(["post-editor-wrapper", editorClass.value])
  4112. }, [
  4113. vue.withDirectives(vue.createElementVNode("textarea", {
  4114. class: vue.normalizeClass(["post-editor", editorId.value]),
  4115. ref_key: "txtRef",
  4116. ref: txtRef,
  4117. onFocus: _cache[0] || (_cache[0] = ($event) => vue.isRef(isFocus) ? isFocus.value = true : isFocus = true),
  4118. onBlur,
  4119. onFocusin,
  4120. placeholder: "请尽量让自己的回复能够对别人有帮助",
  4121. onInput,
  4122. onKeydown,
  4123. onDrop: drop,
  4124. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => content.value = $event)
  4125. }, null, 34), [
  4126. [vue.vModelText, content.value]
  4127. ]),
  4128. vue.createElementVNode("div", _hoisted_1$b, [
  4129. vue.createElementVNode("span", { innerHTML: cursorHtml.value }, null, 8, _hoisted_2$8),
  4130. vue.createElementVNode("span", {
  4131. class: "cursor",
  4132. ref_key: "cursorRef",
  4133. ref: cursorRef
  4134. }, "|", 512)
  4135. ]),
  4136. vue.createElementVNode("div", _hoisted_3$7, [
  4137. vue.createElementVNode("div", _hoisted_4$7, [
  4138. vue.createVNode(vue.unref(Icon), {
  4139. onClick: showEmoticons,
  4140. icon: "streamline:smiley-happy"
  4141. }),
  4142. vue.createElementVNode("div", _hoisted_5$5, [
  4143. vue.createElementVNode("input", {
  4144. type: "file",
  4145. accept: "image/*",
  4146. onChange: _cache[2] || (_cache[2] = (e2) => upload(e2.currentTarget.files[0]))
  4147. }, null, 32),
  4148. vue.createVNode(vue.unref(Icon), { icon: "lets-icons:img-load-box-fill" })
  4149. ]),
  4150. uploadLoading.value ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_6$5, "上传中.....")) : vue.createCommentVNode("", true)
  4151. ]),
  4152. vue.createElementVNode("div", _hoisted_7$4, [
  4153. vue.unref(useType) === "reply-comment" ? (vue.openBlock(), vue.createBlock(BaseButton, {
  4154. key: 0,
  4155. type: "link",
  4156. size: "small",
  4157. style: { "margin-right": "1rem", "cursor": "pointer" },
  4158. onClick: _cache[3] || (_cache[3] = ($event) => emits("close"))
  4159. }, {
  4160. default: vue.withCtx(() => [
  4161. vue.createTextVNode(" 关闭 ")
  4162. ]),
  4163. _: 1
  4164. })) : vue.createCommentVNode("", true),
  4165. vue.createVNode(BaseButton, {
  4166. size: "small",
  4167. disabled: disabled.value,
  4168. loading: loading.value,
  4169. onClick: submit
  4170. }, {
  4171. default: vue.withCtx(() => [
  4172. vue.createTextVNode("回复 ")
  4173. ]),
  4174. _: 1
  4175. }, 8, ["disabled", "loading"])
  4176. ])
  4177. ]),
  4178. vue.withDirectives(vue.createElementVNode("div", {
  4179. class: "emoticon-pack",
  4180. ref_key: "emoticonsRef",
  4181. ref: emoticonsRef
  4182. }, [
  4183. vue.createVNode(vue.unref(Icon), {
  4184. icon: "ic:round-close",
  4185. onClick: _cache[4] || (_cache[4] = ($event) => isShowEmoticons.value = false)
  4186. }),
  4187. _hoisted_8$4,
  4188. vue.createElementVNode("div", _hoisted_9$4, [
  4189. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(classicsEmoticons, (item) => {
  4190. return vue.createElementVNode("img", {
  4191. src: item.high,
  4192. onClick: ($event) => {
  4193. insert(item.name);
  4194. isShowEmoticons.value = false;
  4195. }
  4196. }, null, 8, _hoisted_10$3);
  4197. }), 64))
  4198. ]),
  4199. vue.createElementVNode("div", _hoisted_11$3, [
  4200. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(emojiEmoticons, (item) => {
  4201. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  4202. vue.createElementVNode("div", _hoisted_12$3, vue.toDisplayString(item.title), 1),
  4203. vue.createElementVNode("div", _hoisted_13$3, [
  4204. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.list, (emoji) => {
  4205. return vue.openBlock(), vue.createElementBlock("span", {
  4206. onClick: ($event) => {
  4207. insert(emoji);
  4208. isShowEmoticons.value = false;
  4209. }
  4210. }, vue.toDisplayString(emoji), 9, _hoisted_14$3);
  4211. }), 256))
  4212. ])
  4213. ], 64);
  4214. }), 64))
  4215. ])
  4216. ], 512), [
  4217. [vue.vShow, isShowEmoticons.value]
  4218. ])
  4219. ], 2);
  4220. };
  4221. }
  4222. };
  4223. const PostEditor = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-4522f98e"]]);
  4224. const _hoisted_1$a = {
  4225. key: 0,
  4226. class: "html-wrapper"
  4227. };
  4228. const _hoisted_2$7 = ["innerHTML"];
  4229. const checkHeight = 900;
  4230. const _sfc_main$a = {
  4231. __name: "BaseHtmlRender",
  4232. props: ["html"],
  4233. setup(__props) {
  4234. const config2 = vue.inject("config");
  4235. const props = __props;
  4236. const contentRef = vue.ref(null);
  4237. const mask = vue.ref(false);
  4238. const handOpen = vue.ref(false);
  4239. function mouseup(e2) {
  4240. if (!config2.value.base64)
  4241. return;
  4242. let selectionText = window.win().getSelection().toString();
  4243. if (selectionText) {
  4244. let r2 = selectionText.match(/([A-Za-z0-9+/=]+)/g);
  4245. if (r2) {
  4246. if (r2[0].length < 4)
  4247. return;
  4248. eventBus.emit(CMD.SHOW_TOOLTIP, { text: r2[0], e: e2 });
  4249. }
  4250. }
  4251. }
  4252. vue.watch(config2.value, (newVale) => {
  4253. if (!newVale.contentAutoCollapse) {
  4254. mask.value = false;
  4255. }
  4256. });
  4257. vue.watch([() => contentRef.value, () => props.html], () => {
  4258. if (!contentRef.value || !props.html)
  4259. return;
  4260. if (!config2.value.contentAutoCollapse)
  4261. return;
  4262. contentRef.value.querySelectorAll("img").forEach((item) => {
  4263. item.removeEventListener("load", checkContentHeight);
  4264. item.addEventListener("load", checkContentHeight);
  4265. });
  4266. checkContentHeight();
  4267. }, { immediate: true, flush: "post" });
  4268. function checkContentHeight() {
  4269. if (handOpen.value)
  4270. return;
  4271. let rect = contentRef.value.getBoundingClientRect();
  4272. mask.value = rect.height >= checkHeight;
  4273. }
  4274. return (_ctx, _cache) => {
  4275. return props.html ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$a, [
  4276. vue.createElementVNode("div", {
  4277. class: vue.normalizeClass({ mask: mask.value })
  4278. }, [
  4279. vue.createElementVNode("div", {
  4280. ref_key: "contentRef",
  4281. ref: contentRef,
  4282. innerHTML: props.html,
  4283. onMouseup: mouseup
  4284. }, null, 40, _hoisted_2$7)
  4285. ], 2),
  4286. mask.value ? (vue.openBlock(), vue.createElementBlock("div", {
  4287. key: 0,
  4288. class: "expand",
  4289. onClick: _cache[0] || (_cache[0] = ($event) => {
  4290. mask.value = false;
  4291. handOpen.value = true;
  4292. })
  4293. }, "展开")) : vue.createCommentVNode("", true)
  4294. ])) : vue.createCommentVNode("", true);
  4295. };
  4296. }
  4297. };
  4298. const BaseHtmlRender = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-2c9a538c"]]);
  4299. const _sfc_main$9 = {
  4300. name: "Comment",
  4301. components: { BaseHtmlRender, Author, PostEditor, Point },
  4302. inject: ["post", "postDetailWidth", "show", "isNight", "config"],
  4303. props: {
  4304. modelValue: {
  4305. reply_content: ""
  4306. },
  4307. type: {
  4308. type: String,
  4309. default() {
  4310. return "list";
  4311. }
  4312. }
  4313. },
  4314. data() {
  4315. return {
  4316. edit: false,
  4317. ding: false,
  4318. expand: true,
  4319. expandWrong: false,
  4320. replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
  4321. cssStyle: null,
  4322. floor: this.modelValue.floor
  4323. };
  4324. },
  4325. watch: {
  4326. show(e2) {
  4327. if (e2) {
  4328. this.edit = false;
  4329. }
  4330. },
  4331. postDetailWidth(n2, o) {
  4332. this.checkIsTooLong(n2);
  4333. }
  4334. },
  4335. computed: {
  4336. CommentDisplayType() {
  4337. return CommentDisplayType;
  4338. },
  4339. myClass() {
  4340. return {
  4341. isOp: this.modelValue.isOp,
  4342. isSimple: this.config.viewType === "simple",
  4343. ding: this.ding,
  4344. isLevelOne: this.modelValue.level === 0,
  4345. ["c_" + this.floor]: this.type !== "top"
  4346. };
  4347. }
  4348. },
  4349. mounted() {
  4350. this.checkIsTooLong(this.postDetailWidth);
  4351. },
  4352. methods: {
  4353. checkIsTooLong(postDetailWidth) {
  4354. if (postDetailWidth !== 0) {
  4355. let rect = this.$refs.comment.getBoundingClientRect();
  4356. let ban = postDetailWidth / 2;
  4357. if (ban < rect.width && rect.width < ban + 25 && this.modelValue.children.length) {
  4358. this.expand = false;
  4359. let padding = 2;
  4360. this.cssStyle = {
  4361. padding: "1rem 0",
  4362. width: `calc(${postDetailWidth}px - ${padding}rem)`,
  4363. transform: `translateX(calc(${rect.width - postDetailWidth}px + ${padding}rem))`,
  4364. background: this.isNight ? "#18222d" : "white"
  4365. };
  4366. }
  4367. }
  4368. },
  4369. //高亮一下
  4370. showDing() {
  4371. this.ding = true;
  4372. setTimeout(() => {
  4373. this.ding = false;
  4374. }, 2e3);
  4375. },
  4376. hide() {
  4377. let url = `${window.baseUrl}/ignore/reply/${this.modelValue.id}?once=${this.post.once}`;
  4378. eventBus.emit(CMD.REMOVE, this.modelValue.floor);
  4379. $.post(url).then((res) => {
  4380. eventBus.emit(CMD.REFRESH_ONCE);
  4381. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "隐藏成功" });
  4382. }, (err) => {
  4383. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "隐藏成功,仅本次有效(接口调用失败!)" });
  4384. });
  4385. },
  4386. toggle() {
  4387. this.expand = !this.expand;
  4388. }
  4389. }
  4390. };
  4391. const _withScopeId$6 = (n2) => (vue.pushScopeId("data-v-67807ede"), n2 = n2(), vue.popScopeId(), n2);
  4392. const _hoisted_1$9 = ["data-floor"];
  4393. const _hoisted_2$6 = { class: "comment-content" };
  4394. const _hoisted_3$6 = { class: "right" };
  4395. const _hoisted_4$6 = { class: "w" };
  4396. const _hoisted_5$4 = {
  4397. key: 0,
  4398. class: "wrong-wrapper"
  4399. };
  4400. const _hoisted_6$4 = ["href"];
  4401. const _hoisted_7$3 = { class: "del-line" };
  4402. const _hoisted_8$3 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("i", {
  4403. class: "fa fa-question-circle-o wrong-icon",
  4404. "aria-hidden": "true"
  4405. }, null, -1));
  4406. const _hoisted_9$3 = {
  4407. key: 0,
  4408. class: "warning"
  4409. };
  4410. const _hoisted_10$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4411. const _hoisted_11$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4412. const _hoisted_12$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4413. const _hoisted_13$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4414. const _hoisted_14$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  4415. const _hoisted_15$2 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("a", {
  4416. href: "https://github.com/zyronon/web-scripts/issues",
  4417. target: "_blank"
  4418. }, "这里", -1));
  4419. const _hoisted_16$2 = { class: "simple-wrapper" };
  4420. function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
  4421. const _component_Author = vue.resolveComponent("Author");
  4422. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  4423. const _component_PostEditor = vue.resolveComponent("PostEditor");
  4424. const _component_Comment = vue.resolveComponent("Comment", true);
  4425. return vue.openBlock(), vue.createElementBlock("div", {
  4426. class: vue.normalizeClass(["comment", $options.myClass]),
  4427. ref: "comment",
  4428. "data-floor": $data.floor
  4429. }, [
  4430. vue.createVNode(_component_Author, {
  4431. modelValue: $data.expand,
  4432. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
  4433. comment: $props.modelValue,
  4434. onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
  4435. type: $props.type,
  4436. onHide: $options.hide
  4437. }, null, 8, ["modelValue", "comment", "type", "onHide"]),
  4438. $data.cssStyle && !$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  4439. key: 0,
  4440. class: "more ago",
  4441. onClick: _cache[2] || (_cache[2] = ($event) => $data.expand = !$data.expand)
  4442. }, " 由于嵌套回复层级太深,自动将后续回复隐藏 ")) : vue.createCommentVNode("", true),
  4443. $data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  4444. key: 1,
  4445. class: "comment-content-w",
  4446. style: vue.normalizeStyle($data.cssStyle)
  4447. }, [
  4448. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  4449. key: 0,
  4450. class: "more ago",
  4451. onClick: _cache[3] || (_cache[3] = ($event) => $data.expand = !$data.expand)
  4452. }, " 由于嵌套回复层级太深,自动将以下回复移至可见范围 ")) : vue.createCommentVNode("", true),
  4453. vue.createElementVNode("div", _hoisted_2$6, [
  4454. vue.createElementVNode("div", {
  4455. class: "left expand-line",
  4456. onClick: _cache[4] || (_cache[4] = (...args) => $options.toggle && $options.toggle(...args))
  4457. }),
  4458. vue.createElementVNode("div", _hoisted_3$6, [
  4459. vue.createElementVNode("div", _hoisted_4$6, [
  4460. $props.modelValue.isWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$4, [
  4461. vue.createElementVNode("span", {
  4462. onClick: _cache[5] || (_cache[5] = ($event) => $data.expandWrong = !$data.expandWrong),
  4463. title: "点击楼层号查看提示"
  4464. }, [
  4465. vue.createElementVNode("a", {
  4466. href: "/member/" + $props.modelValue.replyUsers[0]
  4467. }, "@" + vue.toDisplayString($props.modelValue.replyUsers[0]) + "  ", 9, _hoisted_6$4),
  4468. vue.createElementVNode("span", _hoisted_7$3, "#" + vue.toDisplayString($props.modelValue.replyFloor), 1),
  4469. _hoisted_8$3
  4470. ]),
  4471. $data.expandWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$3, [
  4472. vue.createTextVNode(" 这条回复似乎有点问题,指定的楼层号与@的人对应不上 "),
  4473. _hoisted_10$2,
  4474. vue.createTextVNode(" 原因可能有下面几种: "),
  4475. _hoisted_11$2,
  4476. vue.createTextVNode(" 一、屏蔽用户导致楼层塌陷:你屏蔽了A,自A以后的回复的楼层号都会减1 "),
  4477. _hoisted_12$2,
  4478. vue.createTextVNode(" 二、忽略回复导致楼层塌陷:原理同上 "),
  4479. _hoisted_13$2,
  4480. vue.createTextVNode(" 三、层主回复时指定错了楼层号(同一,层主屏蔽了别人,导致楼层塌陷) "),
  4481. _hoisted_14$2,
  4482. vue.createTextVNode(" 四、脚本解析错误,请在 "),
  4483. _hoisted_15$2,
  4484. vue.createTextVNode("反馈 ")
  4485. ])) : vue.createCommentVNode("", true)
  4486. ])) : vue.createCommentVNode("", true),
  4487. $options.config.commentDisplayType === $options.CommentDisplayType.FloorInFloorNoCallUser && this.type !== "top" ? (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  4488. key: 1,
  4489. class: "reply_content",
  4490. html: $props.modelValue.hideCallUserReplyContent
  4491. }, null, 8, ["html"])) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  4492. key: 2,
  4493. class: "reply_content",
  4494. html: $props.modelValue.reply_content
  4495. }, null, 8, ["html"])),
  4496. $data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
  4497. key: 3,
  4498. onClose: _cache[6] || (_cache[6] = ($event) => $data.edit = false),
  4499. replyInfo: $data.replyInfo,
  4500. replyUser: $props.modelValue.username,
  4501. replyFloor: $props.modelValue.floor
  4502. }, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true)
  4503. ]),
  4504. vue.createElementVNode("div", _hoisted_16$2, [
  4505. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index) => {
  4506. return vue.openBlock(), vue.createBlock(_component_Comment, {
  4507. modelValue: $props.modelValue.children[index],
  4508. "onUpdate:modelValue": ($event) => $props.modelValue.children[index] = $event,
  4509. key: index
  4510. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  4511. }), 128))
  4512. ])
  4513. ])
  4514. ]),
  4515. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  4516. key: 1,
  4517. class: "more ago",
  4518. onClick: _cache[7] || (_cache[7] = ($event) => $data.expand = !$data.expand)
  4519. }, " 由于嵌套回复层级太深,自动将以上回复移至可见范围 ")) : vue.createCommentVNode("", true)
  4520. ], 4)) : vue.createCommentVNode("", true)
  4521. ], 10, _hoisted_1$9);
  4522. }
  4523. const Comment = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$4], ["__scopeId", "data-v-67807ede"]]);
  4524. const _sfc_main$8 = {
  4525. name: "Toolbar",
  4526. components: { Icon, BaseLoading },
  4527. inject: [
  4528. "isLogin",
  4529. "post",
  4530. "pageType"
  4531. ],
  4532. data() {
  4533. return {
  4534. timer: null,
  4535. loading: false,
  4536. loading2: false,
  4537. loading3: false
  4538. };
  4539. },
  4540. methods: {
  4541. checkIsLogin(emitName = "") {
  4542. if (!this.isLogin) {
  4543. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录!" });
  4544. return false;
  4545. }
  4546. this.$emit(emitName);
  4547. return true;
  4548. },
  4549. tweet() {
  4550. var _a;
  4551. let username = ((_a = window.user) == null ? void 0 : _a.username) ?? "";
  4552. let url = `https://twitter.com/intent/tweet?url=${location.origin}/t/${this.post.id}?r=${username}&related=v2ex&text=${this.post.title}`;
  4553. window.open(url, "_blank", "width=550,height=370");
  4554. },
  4555. async report() {
  4556. if (!this.checkIsLogin())
  4557. return;
  4558. if (this.loading3)
  4559. return;
  4560. let isReport = this.post.isReport;
  4561. if (isReport) {
  4562. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
  4563. return;
  4564. }
  4565. let url = `${location.origin}/report/topic/${this.post.id}?once=${this.post.once}`;
  4566. this.loading3 = true;
  4567. let apiRes = await fetch(url);
  4568. this.loading3 = false;
  4569. if (apiRes.redirected) {
  4570. let htmlText = await apiRes.text();
  4571. if (htmlText.search("你已对本主题进行了报告")) {
  4572. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "你已对本主题进行了报告" });
  4573. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  4574. eventBus.emit(CMD.MERGE, { isReport: !isReport });
  4575. return;
  4576. }
  4577. }
  4578. eventBus.emit(CMD.REFRESH_ONCE);
  4579. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败,请重试" });
  4580. },
  4581. async toggleIgnore() {
  4582. if (!this.checkIsLogin())
  4583. return;
  4584. let url = `${window.baseUrl}/${this.post.isIgnore ? "unignore" : "ignore"}/topic/${this.post.id}?once=${this.post.once}`;
  4585. if (this.pageType === PageType.Post) {
  4586. this.loading2 = true;
  4587. let apiRes = await window.win().fetch(url);
  4588. if (apiRes.redirected) {
  4589. if (!this.post.isIgnore) {
  4590. window.win().location = window.baseUrl;
  4591. }
  4592. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  4593. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  4594. } else {
  4595. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略失败" });
  4596. }
  4597. this.loading2 = false;
  4598. } else {
  4599. if (this.post.isIgnore) {
  4600. this.loading2 = true;
  4601. } else {
  4602. eventBus.emit(CMD.IGNORE);
  4603. }
  4604. let apiRes = await window.win().fetch(url);
  4605. if (apiRes.redirected) {
  4606. if (this.post.isIgnore) {
  4607. eventBus.emit(CMD.REFRESH_ONCE);
  4608. }
  4609. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  4610. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  4611. } else {
  4612. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略成功,仅本次有效(接口调用失败!)" });
  4613. }
  4614. this.loading2 = false;
  4615. }
  4616. },
  4617. async toggleFavorite() {
  4618. if (!this.checkIsLogin())
  4619. return;
  4620. if (this.loading)
  4621. return;
  4622. let isFavorite = this.post.isFavorite;
  4623. if (!isFavorite && config.collectBrowserNotice) {
  4624. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "别忘记按Command/Cmd/CTRL + D添加到书签哦" });
  4625. }
  4626. let url = `${location.origin}/${isFavorite ? "unfavorite" : "favorite"}/topic/${this.post.id}?once=${this.post.once}`;
  4627. this.loading = true;
  4628. let apiRes = await fetch(url);
  4629. this.loading = false;
  4630. if (apiRes.redirected) {
  4631. let htmlText = await apiRes.text();
  4632. if (htmlText.search(isFavorite ? "加入收藏" : "取消收藏")) {
  4633. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: isFavorite ? "取消成功" : "收藏成功" });
  4634. eventBus.emit(CMD.MERGE, { collectCount: isFavorite ? this.post.collectCount - 1 : this.post.collectCount + 1 });
  4635. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  4636. eventBus.emit(CMD.MERGE, { isFavorite: !isFavorite });
  4637. return;
  4638. }
  4639. }
  4640. eventBus.emit(CMD.REFRESH_ONCE);
  4641. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败" });
  4642. }
  4643. }
  4644. };
  4645. const _withScopeId$5 = (n2) => (vue.pushScopeId("data-v-e3df61b2"), n2 = n2(), vue.popScopeId(), n2);
  4646. const _hoisted_1$8 = { class: "toolbar" };
  4647. const _hoisted_2$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复", -1));
  4648. const _hoisted_3$5 = {
  4649. key: 0,
  4650. class: "tool no-hover"
  4651. };
  4652. const _hoisted_4$5 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("span", null, "Tweet", -1));
  4653. function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
  4654. const _component_Icon = vue.resolveComponent("Icon");
  4655. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  4656. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
  4657. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true),
  4658. vue.createElementVNode("div", {
  4659. class: "tool",
  4660. onClick: _cache[0] || (_cache[0] = ($event) => $options.checkIsLogin("reply"))
  4661. }, [
  4662. vue.createVNode(_component_Icon, { icon: "mynaui:message" }),
  4663. _hoisted_2$5
  4664. ]),
  4665. vue.createElementVNode("div", {
  4666. class: vue.normalizeClass(["tool", { disabled: $data.loading }]),
  4667. onClick: _cache[1] || (_cache[1] = (...args) => $options.toggleFavorite && $options.toggleFavorite(...args))
  4668. }, [
  4669. $data.loading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  4670. key: 0,
  4671. size: "small"
  4672. })) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  4673. $options.post.isFavorite ? (vue.openBlock(), vue.createBlock(_component_Icon, {
  4674. key: 0,
  4675. color: "rgb(224,42,42)",
  4676. icon: "iconoir:star-solid"
  4677. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  4678. key: 1,
  4679. icon: "iconoir:star"
  4680. }))
  4681. ], 64)),
  4682. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isFavorite ? "取消" : "") + "收藏", 1)
  4683. ], 2),
  4684. $options.post.collectCount !== 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$5, [
  4685. vue.createElementVNode("span", null, vue.toDisplayString($options.post.collectCount + "人收藏"), 1)
  4686. ])) : vue.createCommentVNode("", true),
  4687. vue.createElementVNode("div", {
  4688. class: "tool",
  4689. onClick: _cache[2] || (_cache[2] = (...args) => $options.tweet && $options.tweet(...args))
  4690. }, [
  4691. vue.createVNode(_component_Icon, { icon: "uil:share" }),
  4692. _hoisted_4$5
  4693. ]),
  4694. vue.createElementVNode("div", {
  4695. class: vue.normalizeClass(["tool", { "disabled": $data.loading2 }]),
  4696. onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleIgnore && $options.toggleIgnore(...args))
  4697. }, [
  4698. $data.loading2 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  4699. key: 0,
  4700. size: "small"
  4701. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  4702. key: 1,
  4703. icon: "fluent:eye-hide-24-regular"
  4704. })),
  4705. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isIgnore ? "取消忽略" : "忽略"), 1)
  4706. ], 2),
  4707. vue.createElementVNode("div", {
  4708. class: vue.normalizeClass(["tool", { "disabled": $data.loading3 }]),
  4709. onClick: _cache[4] || (_cache[4] = (...args) => $options.report && $options.report(...args))
  4710. }, [
  4711. $data.loading3 ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, {
  4712. key: 0,
  4713. size: "small"
  4714. })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  4715. key: 1,
  4716. class: "black",
  4717. icon: "solar:danger-triangle-outline"
  4718. })),
  4719. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isReport ? "你已对本主题进行了报告" : "报告"), 1)
  4720. ], 2)
  4721. ]);
  4722. }
  4723. const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$3], ["__scopeId", "data-v-e3df61b2"]]);
  4724. const _withScopeId$4 = (n2) => (vue.pushScopeId("data-v-87050bc7"), n2 = n2(), vue.popScopeId(), n2);
  4725. const _hoisted_1$7 = ["href"];
  4726. const _hoisted_2$4 = ["src"];
  4727. const _hoisted_3$4 = { class: "texts" };
  4728. const _hoisted_4$4 = {
  4729. key: 0,
  4730. class: "point"
  4731. };
  4732. const _hoisted_5$3 = { class: "link-num" };
  4733. const _hoisted_6$3 = { class: "my-tag" };
  4734. const _hoisted_7$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  4735. const _hoisted_8$2 = {
  4736. key: 2,
  4737. class: "ago"
  4738. };
  4739. const _hoisted_9$2 = {
  4740. key: 3,
  4741. class: "mod"
  4742. };
  4743. const _hoisted_10$1 = {
  4744. key: 4,
  4745. class: "owner"
  4746. };
  4747. const _hoisted_11$1 = ["href"];
  4748. const _hoisted_12$1 = {
  4749. key: 5,
  4750. class: "owner"
  4751. };
  4752. const _hoisted_13$1 = {
  4753. key: 6,
  4754. class: "mod"
  4755. };
  4756. const _hoisted_14$1 = {
  4757. key: 7,
  4758. class: "ago"
  4759. };
  4760. const _hoisted_15$1 = { class: "my-tag" };
  4761. const _hoisted_16$1 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  4762. const _hoisted_17$1 = {
  4763. key: 9,
  4764. class: "point"
  4765. };
  4766. const _hoisted_18$1 = { class: "link-num" };
  4767. const _hoisted_19$1 = ["href"];
  4768. const _hoisted_20$1 = ["src"];
  4769. const _hoisted_21$1 = { class: "Author-right" };
  4770. const _hoisted_22$1 = { class: "floor" };
  4771. const _hoisted_23$1 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  4772. const _hoisted_24$1 = [
  4773. _hoisted_23$1
  4774. ];
  4775. const _sfc_main$7 = {
  4776. __name: "SingleComment",
  4777. props: {
  4778. comment: {
  4779. reply_content: ""
  4780. },
  4781. isRight: {
  4782. type: Boolean,
  4783. default() {
  4784. return false;
  4785. }
  4786. }
  4787. },
  4788. setup(__props) {
  4789. const config2 = vue.inject("config");
  4790. const isLogin = vue.inject("isLogin");
  4791. const tags = vue.inject("tags");
  4792. const props = __props;
  4793. const myTags = vue.computed(() => {
  4794. return tags[props.comment.username] ?? [];
  4795. });
  4796. function jump() {
  4797. eventBus.emit(CMD.JUMP, props.comment.floor);
  4798. }
  4799. return (_ctx, _cache) => {
  4800. return vue.openBlock(), vue.createElementBlock("div", {
  4801. class: vue.normalizeClass(["comment", { isSimple: vue.unref(config2).viewType === "simple" }]),
  4802. ref: "comment"
  4803. }, [
  4804. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  4805. key: 0,
  4806. class: "avatar",
  4807. href: `/member/${__props.comment.username}`
  4808. }, [
  4809. vue.createElementVNode("img", {
  4810. src: __props.comment.avatar,
  4811. alt: ""
  4812. }, null, 8, _hoisted_2$4)
  4813. ], 8, _hoisted_1$7)) : vue.createCommentVNode("", true),
  4814. vue.createElementVNode("div", {
  4815. class: vue.normalizeClass(["comment-body", { isRight: __props.isRight }])
  4816. }, [
  4817. vue.createElementVNode("div", _hoisted_3$4, [
  4818. __props.comment.thankCount && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$4, [
  4819. __props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  4820. key: 0,
  4821. color: "rgb(224,42,42)",
  4822. icon: "icon-park-solid:like"
  4823. })) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  4824. key: 1,
  4825. color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
  4826. icon: "icon-park-outline:like"
  4827. }, null, 8, ["color"])),
  4828. vue.createElementVNode("div", _hoisted_5$3, vue.toDisplayString(__props.comment.thankCount), 1)
  4829. ])) : vue.createCommentVNode("", true),
  4830. vue.unref(isLogin) && vue.unref(config2).openTag && __props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(myTags.value, (i) => {
  4831. return vue.openBlock(), vue.createElementBlock("span", _hoisted_6$3, [
  4832. _hoisted_7$2,
  4833. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  4834. ]);
  4835. }), 256)) : vue.createCommentVNode("", true),
  4836. __props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_8$2, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  4837. __props.comment.isMod && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$2, "MOD")) : vue.createCommentVNode("", true),
  4838. __props.comment.isOp && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$1, "OP")) : vue.createCommentVNode("", true),
  4839. vue.createElementVNode("a", {
  4840. href: `/member/${__props.comment.username}`,
  4841. class: "username"
  4842. }, vue.toDisplayString(__props.comment.username), 9, _hoisted_11$1),
  4843. __props.comment.isOp && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$1, "OP")) : vue.createCommentVNode("", true),
  4844. __props.comment.isMod && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$1, "MOD")) : vue.createCommentVNode("", true),
  4845. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_14$1, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  4846. vue.unref(isLogin) && vue.unref(config2).openTag && !__props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 8 }, vue.renderList(myTags.value, (i) => {
  4847. return vue.openBlock(), vue.createElementBlock("span", _hoisted_15$1, [
  4848. _hoisted_16$1,
  4849. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  4850. ]);
  4851. }), 256)) : vue.createCommentVNode("", true),
  4852. __props.comment.thankCount && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_17$1, [
  4853. __props.comment.isThanked ? (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  4854. key: 0,
  4855. color: "rgb(224,42,42)",
  4856. icon: "icon-park-solid:like"
  4857. })) : (vue.openBlock(), vue.createBlock(vue.unref(Icon), {
  4858. key: 1,
  4859. color: !__props.comment.thankCount ? null : "rgb(224,42,42)",
  4860. icon: "icon-park-outline:like"
  4861. }, null, 8, ["color"])),
  4862. vue.createElementVNode("div", _hoisted_18$1, vue.toDisplayString(__props.comment.thankCount), 1)
  4863. ])) : vue.createCommentVNode("", true)
  4864. ]),
  4865. vue.createVNode(BaseHtmlRender, {
  4866. class: "reply_content",
  4867. html: __props.comment.reply_content
  4868. }, null, 8, ["html"])
  4869. ], 2),
  4870. __props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  4871. key: 1,
  4872. class: "avatar",
  4873. href: `/member/${__props.comment.username}`
  4874. }, [
  4875. vue.createElementVNode("img", {
  4876. src: __props.comment.avatar,
  4877. alt: ""
  4878. }, null, 8, _hoisted_20$1)
  4879. ], 8, _hoisted_19$1)) : vue.createCommentVNode("", true),
  4880. vue.createElementVNode("div", _hoisted_21$1, [
  4881. vue.createElementVNode("div", _hoisted_22$1, vue.toDisplayString(__props.comment.floor), 1),
  4882. vue.createElementVNode("div", {
  4883. class: "tool jump",
  4884. onClick: jump
  4885. }, _hoisted_24$1)
  4886. ])
  4887. ], 2);
  4888. };
  4889. }
  4890. };
  4891. const SingleComment = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-87050bc7"]]);
  4892. const _sfc_main$6 = {
  4893. name: "detail",
  4894. components: {
  4895. BaseSelect,
  4896. BaseButton,
  4897. SingleComment,
  4898. PopConfirm,
  4899. Comment,
  4900. PostEditor,
  4901. Point,
  4902. Toolbar,
  4903. BaseHtmlRender,
  4904. Tooltip,
  4905. BaseLoading,
  4906. Icon
  4907. },
  4908. inject: ["allReplyUsers", "post", "isMobile", "tags", "isLogin", "config", "pageType", "isNight"],
  4909. provide() {
  4910. return {
  4911. postDetailWidth: vue.computed(() => this.postDetailWidth)
  4912. };
  4913. },
  4914. props: {
  4915. modelValue: {
  4916. type: Boolean,
  4917. default() {
  4918. return false;
  4919. }
  4920. },
  4921. loading: {
  4922. type: Boolean,
  4923. default() {
  4924. return false;
  4925. }
  4926. },
  4927. refreshLoading: {
  4928. type: Boolean,
  4929. default() {
  4930. return false;
  4931. }
  4932. },
  4933. displayType: CommentDisplayType.FloorInFloorNoCallUser
  4934. },
  4935. data() {
  4936. return {
  4937. isSticky: false,
  4938. selectCallIndex: 0,
  4939. postDetailWidth: 0,
  4940. showCallList: false,
  4941. showRelationReply: false,
  4942. replyText: "",
  4943. callStyle: {
  4944. top: 0,
  4945. left: 0
  4946. },
  4947. targetUser: {
  4948. left: [],
  4949. right: "",
  4950. rightFloor: -1
  4951. },
  4952. currentFloor: "",
  4953. showOpTag: false
  4954. };
  4955. },
  4956. computed: {
  4957. canAppend() {
  4958. if (this.isMy) {
  4959. let create = new Date(this.post.createDate);
  4960. return Date.now() - create.valueOf() > 1e3 * 60 * 30;
  4961. }
  4962. return false;
  4963. },
  4964. canEditMove() {
  4965. if (this.isMy) {
  4966. let create = new Date(this.post.createDate);
  4967. return Date.now() - create.valueOf() < 1e3 * 60 * 10;
  4968. }
  4969. return false;
  4970. },
  4971. isMy() {
  4972. return this.post.member.username === window.user.username;
  4973. },
  4974. myTags() {
  4975. return this.tags[this.post.member.username] ?? [];
  4976. },
  4977. CommentDisplayType() {
  4978. return CommentDisplayType;
  4979. },
  4980. isPost() {
  4981. return this.pageType === PageType.Post;
  4982. },
  4983. filterCallList() {
  4984. if (this.showCallList) {
  4985. let list = ["管理员", "所有人"].concat(this.allReplyUsers);
  4986. if (this.replyText)
  4987. return list.filter((i) => i.search(this.replyText) > -1);
  4988. return list;
  4989. }
  4990. return [];
  4991. },
  4992. topReply() {
  4993. return this.post.replyList.filter((v) => v.thankCount >= this.config.topReplyLoveMinCount).sort((a, b) => b.thankCount - a.thankCount).slice(0, this.config.topReplyCount);
  4994. },
  4995. replyList() {
  4996. if ([CommentDisplayType.FloorInFloor, CommentDisplayType.FloorInFloorNoCallUser].includes(this.displayType))
  4997. return this.post.nestedReplies;
  4998. if (this.displayType === CommentDisplayType.Like) {
  4999. return window.clone(this.post.nestedReplies).sort((a, b) => b.thankCount - a.thankCount);
  5000. }
  5001. if (this.displayType === CommentDisplayType.New) {
  5002. return window.clone(this.post.replyList).reverse();
  5003. }
  5004. if (this.displayType === CommentDisplayType.V2exOrigin)
  5005. return this.post.replyList;
  5006. if (this.displayType === CommentDisplayType.FloorInFloorNested)
  5007. return this.post.nestedRedundReplies;
  5008. if (this.displayType === CommentDisplayType.OnlyOp)
  5009. return this.post.replyList.filter((v) => {
  5010. var _a;
  5011. return v.username === ((_a = this.post.member) == null ? void 0 : _a.username);
  5012. });
  5013. return [];
  5014. },
  5015. //关联回复
  5016. relationReply() {
  5017. if (this.targetUser.left.length && this.targetUser.right) {
  5018. return this.post.replyList.filter((v) => {
  5019. if (this.targetUser.left.includes(v.username)) {
  5020. if (v.floor > this.targetUser.rightFloor) {
  5021. if (v.replyUsers.includes(this.targetUser.right)) {
  5022. return true;
  5023. }
  5024. } else {
  5025. return true;
  5026. }
  5027. }
  5028. if (v.username === this.targetUser.right) {
  5029. for (let i = 0; i < this.targetUser.left.length; i++) {
  5030. if (v.replyUsers.includes(this.targetUser.left[i])) {
  5031. return true;
  5032. }
  5033. }
  5034. }
  5035. });
  5036. }
  5037. return [];
  5038. }
  5039. },
  5040. watch: {
  5041. "post.id"(n2, o) {
  5042. if (this.$refs["post-editor"]) {
  5043. this.$refs["post-editor"].content = "";
  5044. vue.nextTick(() => {
  5045. var _a, _b;
  5046. (_b = (_a = this.$refs) == null ? void 0 : _a.detail) == null ? void 0 : _b.scrollTo({ top: 0 });
  5047. });
  5048. }
  5049. },
  5050. "post.headerTemplate"(n2, o) {
  5051. let mountEl = document.querySelector(".main-wrapper .post-wrapper .html-wrapper .header");
  5052. if (mountEl) {
  5053. this.showOpTag = true;
  5054. }
  5055. },
  5056. modelValue: {
  5057. handler(newVal) {
  5058. if (this.isPost) {
  5059. return;
  5060. }
  5061. if (newVal) {
  5062. document.body.style.overflow = "hidden";
  5063. if (!window.history.state) {
  5064. window.history.pushState({}, 0, this.post.href);
  5065. }
  5066. this.currentFloor = "";
  5067. vue.nextTick(() => {
  5068. var _a, _b;
  5069. window.document.title = this.post.title ?? "V2EX";
  5070. (_b = (_a = this.$refs) == null ? void 0 : _a.main) == null ? void 0 : _b.focus();
  5071. });
  5072. } else {
  5073. document.body.style.overflow = "unset";
  5074. window.document.title = "V2EX";
  5075. this.isSticky = false;
  5076. this.showRelationReply = false;
  5077. if (window.history.state) {
  5078. window.history.back();
  5079. }
  5080. }
  5081. }
  5082. }
  5083. },
  5084. mounted() {
  5085. setTimeout(() => {
  5086. var _a;
  5087. this.postDetailWidth = ((_a = this.$refs.mainWrapper) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
  5088. });
  5089. if (this.isLogin) {
  5090. const observer = new IntersectionObserver(
  5091. ([e2]) => e2.target.toggleAttribute("stuck", e2.intersectionRatio < 1),
  5092. { threshold: [1] }
  5093. );
  5094. observer.observe(this.$refs.replyBox);
  5095. window.addEventListener("keydown", this.onKeyDown);
  5096. }
  5097. eventBus.on(CMD.SHOW_CALL, (val) => {
  5098. if (val.show) {
  5099. this.showCallList = true;
  5100. this.replyText = val.text;
  5101. if (this.isPost) {
  5102. this.callStyle.top = val.top + $(window.win()).scrollTop() + -40 + "px";
  5103. } else {
  5104. this.callStyle.top = val.top + $(".post-detail").scrollTop() + 15 + "px";
  5105. }
  5106. this.callStyle.left = val.left - $(".main")[0].getBoundingClientRect().left + 10 + "px";
  5107. if (this.selectCallIndex >= this.filterCallList.length) {
  5108. this.selectCallIndex = 0;
  5109. }
  5110. } else {
  5111. this.replyText = "";
  5112. this.showCallList = false;
  5113. this.selectCallIndex = 0;
  5114. }
  5115. });
  5116. eventBus.on(CMD.RELATION_REPLY, (val) => {
  5117. this.targetUser = val;
  5118. this.showRelationReply = true;
  5119. });
  5120. eventBus.on(CMD.JUMP, this.jump);
  5121. if (this.isPost) {
  5122. window.addEventListener("scroll", this.debounceScroll);
  5123. }
  5124. },
  5125. beforeUnmount() {
  5126. window.removeEventListener("keydown", this.onKeyDown);
  5127. eventBus.off(CMD.SHOW_CALL);
  5128. },
  5129. methods: {
  5130. addTag() {
  5131. eventBus.emit(CMD.ADD_TAG, this.post.member.username);
  5132. },
  5133. removeTag(tag) {
  5134. eventBus.emit(CMD.REMOVE_TAG, { username: this.post.member.username, tag });
  5135. },
  5136. stop(e2) {
  5137. },
  5138. jump(floor) {
  5139. let lastItem = this.replyList[this.replyList.length - 1];
  5140. if (floor === "") {
  5141. floor = lastItem.floor;
  5142. } else {
  5143. try {
  5144. floor = Number(floor);
  5145. } catch (e2) {
  5146. floor = lastItem.floor;
  5147. }
  5148. if (floor === 0) {
  5149. floor = 1;
  5150. }
  5151. if (floor > lastItem.floor)
  5152. floor = lastItem.floor;
  5153. }
  5154. if (!this.post.replyList.length) {
  5155. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "没有回复可跳转!" });
  5156. return;
  5157. }
  5158. if (floor > this.post.replyList.length) {
  5159. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  5160. return;
  5161. }
  5162. let comment = $(`.c_${floor}`);
  5163. if (!comment.length) {
  5164. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  5165. return;
  5166. }
  5167. comment[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
  5168. comment.addClass("ding");
  5169. this.currentFloor = floor + 1;
  5170. setTimeout(() => {
  5171. comment.removeClass("ding");
  5172. }, 2e3);
  5173. },
  5174. collapseTopReplyList() {
  5175. $(this.$refs.topReply).slideToggle("fast");
  5176. },
  5177. goBottom() {
  5178. this.isSticky = false;
  5179. setTimeout(() => {
  5180. if (this.isPost) {
  5181. let body = $("body , html");
  5182. let scrollHeight = body.prop("scrollHeight");
  5183. body.animate({ scrollTop: scrollHeight - 850 }, 300);
  5184. } else {
  5185. this.$refs.detail.scrollTo({ top: this.$refs.detail.scrollHeight, behavior: "smooth" });
  5186. }
  5187. });
  5188. },
  5189. close(from) {
  5190. if (this.isPost)
  5191. return;
  5192. if (from === "space") {
  5193. if (this.config.closePostDetailBySpace) {
  5194. this.$emit("update:modelValue", false);
  5195. }
  5196. } else {
  5197. this.$emit("update:modelValue", false);
  5198. }
  5199. },
  5200. setCall(e2) {
  5201. eventBus.emit(CMD.SET_CALL, e2);
  5202. this.showCallList = false;
  5203. },
  5204. onKeyDown(e2) {
  5205. if (!this.modelValue)
  5206. return;
  5207. if (!this.showCallList)
  5208. return;
  5209. let length = this.filterCallList.slice(0, 10).length;
  5210. if (e2.keyCode === 13) {
  5211. this.setCall(this.filterCallList[this.selectCallIndex]);
  5212. e2.preventDefault();
  5213. }
  5214. if (e2.keyCode === 38) {
  5215. this.selectCallIndex--;
  5216. if (this.selectCallIndex < 0) {
  5217. this.selectCallIndex = length - 1;
  5218. }
  5219. e2.preventDefault();
  5220. }
  5221. if (e2.keyCode === 40) {
  5222. this.selectCallIndex++;
  5223. if (this.selectCallIndex > length - 1) {
  5224. this.selectCallIndex = 0;
  5225. }
  5226. e2.preventDefault();
  5227. }
  5228. },
  5229. changeOption(item) {
  5230. this.$emit("update:displayType", item);
  5231. },
  5232. addThank() {
  5233. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "add" });
  5234. },
  5235. recallThank() {
  5236. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "recall" });
  5237. },
  5238. scrollTop() {
  5239. if (this.isPost) {
  5240. $("body , html").animate({ scrollTop: 0 }, 300);
  5241. } else {
  5242. this.$refs.detail.scrollTo({ top: 0, behavior: "smooth" });
  5243. }
  5244. }
  5245. }
  5246. };
  5247. const _withScopeId$3 = (n2) => (vue.pushScopeId("data-v-165fdc78"), n2 = n2(), vue.popScopeId(), n2);
  5248. const _hoisted_1$6 = { class: "my-box post-wrapper" };
  5249. const _hoisted_2$3 = { class: "header" };
  5250. const _hoisted_3$3 = { class: "fr" };
  5251. const _hoisted_4$3 = ["href"];
  5252. const _hoisted_5$2 = ["src", "alt"];
  5253. const _hoisted_6$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("a", { href: "/" }, "V2EX", -1));
  5254. const _hoisted_7$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "chevron" }, "  ›  ", -1));
  5255. const _hoisted_8$1 = ["href"];
  5256. const _hoisted_9$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sep10" }, null, -1));
  5257. const _hoisted_10 = ["id"];
  5258. const _hoisted_11 = ["onclick"];
  5259. const _hoisted_12 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-up" }, null, -1));
  5260. const _hoisted_13 = ["onclick"];
  5261. const _hoisted_14 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-chevron-down" }, null, -1));
  5262. const _hoisted_15 = [
  5263. _hoisted_14
  5264. ];
  5265. const _hoisted_16 = { class: "gray" };
  5266. const _hoisted_17 = ["href"];
  5267. const _hoisted_18 = ["title"];
  5268. const _hoisted_19 = ["href"];
  5269. const _hoisted_20 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("li", { class: "fa fa-info-circle" }, null, -1));
  5270. const _hoisted_21 = [
  5271. _hoisted_20
  5272. ];
  5273. const _hoisted_22 = ["href"];
  5274. const _hoisted_23 = ["href"];
  5275. const _hoisted_24 = ["href"];
  5276. const _hoisted_25 = { class: "my-tag" };
  5277. const _hoisted_26 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  5278. const _hoisted_27 = ["onClick"];
  5279. const _hoisted_28 = {
  5280. key: 0,
  5281. class: "my-box"
  5282. };
  5283. const _hoisted_29 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "高赞回复", -1));
  5284. const _hoisted_30 = { class: "top-reply" };
  5285. const _hoisted_31 = { class: "tool" };
  5286. const _hoisted_32 = { ref: "topReply" };
  5287. const _hoisted_33 = {
  5288. key: 1,
  5289. class: "my-box my-cell"
  5290. };
  5291. const _hoisted_34 = ["innerHTML"];
  5292. const _hoisted_35 = { class: "my-box comment-wrapper" };
  5293. const _hoisted_36 = {
  5294. key: 0,
  5295. class: "my-cell flex"
  5296. };
  5297. const _hoisted_37 = { key: 0 };
  5298. const _hoisted_38 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("strong", { class: "snow" }, "•", -1));
  5299. const _hoisted_39 = ["innerHTML"];
  5300. const _hoisted_40 = {
  5301. key: 0,
  5302. class: "loading-wrapper"
  5303. };
  5304. const _hoisted_41 = {
  5305. key: 1,
  5306. class: "comments"
  5307. };
  5308. const _hoisted_42 = {
  5309. key: 2,
  5310. id: "no-comments-yet"
  5311. };
  5312. const _hoisted_43 = { class: "my-cell flex" };
  5313. const _hoisted_44 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "添加一条新回复", -1));
  5314. const _hoisted_45 = { class: "notice-right gray" };
  5315. const _hoisted_46 = { class: "p1" };
  5316. const _hoisted_47 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "上下文", -1));
  5317. const _hoisted_48 = { class: "top-reply" };
  5318. const _hoisted_49 = ["onClick"];
  5319. function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
  5320. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  5321. const _component_Point = vue.resolveComponent("Point");
  5322. const _component_Toolbar = vue.resolveComponent("Toolbar");
  5323. const _component_Icon = vue.resolveComponent("Icon");
  5324. const _component_Tooltip = vue.resolveComponent("Tooltip");
  5325. const _component_Comment = vue.resolveComponent("Comment");
  5326. const _component_BaseSelect = vue.resolveComponent("BaseSelect");
  5327. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  5328. const _component_PostEditor = vue.resolveComponent("PostEditor");
  5329. const _component_SingleComment = vue.resolveComponent("SingleComment");
  5330. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  5331. class: vue.normalizeClass(["post-detail", [$options.isNight ? "isNight" : "", $options.pageType, $options.isMobile ? "mobile" : ""]]),
  5332. ref: "detail",
  5333. onKeydown: _cache[19] || (_cache[19] = vue.withKeys(($event) => $options.close(), ["esc"])),
  5334. onScroll: _cache[20] || (_cache[20] = (...args) => _ctx.debounceScroll && _ctx.debounceScroll(...args)),
  5335. onClick: _cache[21] || (_cache[21] = ($event) => $options.close("space"))
  5336. }, [
  5337. vue.createElementVNode("div", {
  5338. ref: "main",
  5339. class: "main",
  5340. tabindex: "1",
  5341. onClick: _cache[18] || (_cache[18] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  5342. }, [
  5343. vue.createElementVNode("div", {
  5344. class: "main-wrapper",
  5345. ref: "mainWrapper",
  5346. style: vue.normalizeStyle({ width: $options.config.postWidth })
  5347. }, [
  5348. vue.createElementVNode("div", _hoisted_1$6, [
  5349. vue.createElementVNode("div", _hoisted_2$3, [
  5350. vue.createElementVNode("div", _hoisted_3$3, [
  5351. vue.createElementVNode("a", {
  5352. href: `/member/${$options.post.member.username}`,
  5353. style: { "width": "73px", "height": "73px", "display": "inline-block" }
  5354. }, [
  5355. $options.post.member.avatar_large ? (vue.openBlock(), vue.createElementBlock("img", {
  5356. key: 0,
  5357. src: $options.post.member.avatar_large,
  5358. class: "avatar",
  5359. style: { "width": "73px", "height": "73px" },
  5360. border: "0",
  5361. align: "default",
  5362. alt: $options.post.member.username
  5363. }, null, 8, _hoisted_5$2)) : vue.createCommentVNode("", true)
  5364. ], 8, _hoisted_4$3)
  5365. ]),
  5366. _hoisted_6$2,
  5367. _hoisted_7$1,
  5368. vue.createElementVNode("a", {
  5369. href: $options.post.node.url
  5370. }, vue.toDisplayString($options.post.node.title), 9, _hoisted_8$1),
  5371. _hoisted_9$1,
  5372. vue.createElementVNode("h1", null, vue.toDisplayString($options.post.title), 1),
  5373. !$options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", {
  5374. key: 0,
  5375. id: `topic_${$options.post.id}_votes`,
  5376. class: "votes"
  5377. }, [
  5378. vue.createElementVNode("a", {
  5379. href: "javascript:",
  5380. onclick: `upVoteTopic(${$options.post.id});`,
  5381. class: "vote"
  5382. }, [
  5383. _hoisted_12,
  5384. vue.createTextVNode("   ")
  5385. ], 8, _hoisted_11),
  5386. vue.createTextVNode("   "),
  5387. vue.createElementVNode("a", {
  5388. href: "javascript:",
  5389. onclick: `downVoteTopic(${$options.post.id});`,
  5390. class: "vote"
  5391. }, _hoisted_15, 8, _hoisted_13)
  5392. ], 8, _hoisted_10)) : vue.createCommentVNode("", true),
  5393. vue.createTextVNode("   "),
  5394. vue.createElementVNode("small", _hoisted_16, [
  5395. vue.createElementVNode("a", {
  5396. href: `/member/${$options.post.member.username}`
  5397. }, vue.toDisplayString($options.post.member.username), 9, _hoisted_17),
  5398. vue.createTextVNode(" · "),
  5399. $options.post.member.createDate ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  5400. vue.createElementVNode("span", {
  5401. class: vue.normalizeClass($options.post.member.isNew && "danger")
  5402. }, vue.toDisplayString($options.post.member.createDate), 3),
  5403. vue.createTextVNode(" · ")
  5404. ], 64)) : vue.createCommentVNode("", true),
  5405. $options.post.createDateAgo ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  5406. vue.createElementVNode("span", {
  5407. title: $options.post.createDate
  5408. }, vue.toDisplayString($options.post.createDateAgo), 9, _hoisted_18),
  5409. vue.createTextVNode(" · ")
  5410. ], 64)) : vue.createCommentVNode("", true),
  5411. vue.createTextVNode(" " + vue.toDisplayString($options.post.clickCount) + " 次点击 ", 1),
  5412. $options.isMy ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
  5413. vue.createTextVNode("   "),
  5414. vue.createElementVNode("a", {
  5415. href: `/t/${$options.post.id}/info`
  5416. }, _hoisted_21, 8, _hoisted_19),
  5417. vue.createTextVNode("   "),
  5418. $options.canAppend ? (vue.openBlock(), vue.createElementBlock("a", {
  5419. key: 0,
  5420. href: `/append/topic/${$options.post.id}`,
  5421. class: "op"
  5422. }, "APPEND", 8, _hoisted_22)) : vue.createCommentVNode("", true),
  5423. $options.canEditMove ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  5424. vue.createElementVNode("a", {
  5425. href: `/move/topic/${$options.post.id}`,
  5426. class: "op"
  5427. }, "MOVE", 8, _hoisted_23),
  5428. vue.createTextVNode("  "),
  5429. vue.createElementVNode("a", {
  5430. href: `/edit/topic/${$options.post.id}`,
  5431. class: "op"
  5432. }, "EDIT", 8, _hoisted_24)
  5433. ], 64)) : vue.createCommentVNode("", true)
  5434. ], 64)) : vue.createCommentVNode("", true)
  5435. ]),
  5436. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  5437. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  5438. return vue.openBlock(), vue.createElementBlock("span", _hoisted_25, [
  5439. _hoisted_26,
  5440. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  5441. vue.createElementVNode("i", {
  5442. class: "fa fa-trash-o remove",
  5443. onClick: ($event) => $options.removeTag(i)
  5444. }, null, 8, _hoisted_27)
  5445. ]);
  5446. }), 256)),
  5447. vue.createElementVNode("span", {
  5448. class: "add-tag ago",
  5449. onClick: _cache[0] || (_cache[0] = (...args) => $options.addTag && $options.addTag(...args)),
  5450. title: "添加标签"
  5451. }, "+")
  5452. ], 64)) : vue.createCommentVNode("", true)
  5453. ]),
  5454. $options.post.headerTemplate ? (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  5455. key: 0,
  5456. html: $options.post.headerTemplate
  5457. }, null, 8, ["html"])) : (vue.openBlock(), vue.createBlock(_component_BaseHtmlRender, {
  5458. key: 1,
  5459. html: $options.post.jsonContent
  5460. }, null, 8, ["html"])),
  5461. vue.createVNode(_component_Toolbar, {
  5462. onReply: _cache[1] || (_cache[1] = ($event) => $data.isSticky = !$data.isSticky)
  5463. }, {
  5464. default: vue.withCtx(() => [
  5465. vue.createVNode(_component_Point, {
  5466. onAddThank: $options.addThank,
  5467. onRecallThank: $options.recallThank,
  5468. item: {
  5469. isThanked: $options.post.isThanked,
  5470. thankCount: $options.post.thankCount,
  5471. username: $options.post.username
  5472. },
  5473. "api-url": "topic/" + $options.post.id
  5474. }, null, 8, ["onAddThank", "onRecallThank", "item", "api-url"])
  5475. ]),
  5476. _: 1
  5477. })
  5478. ]),
  5479. $options.topReply.length && $options.config.showTopReply ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_28, [
  5480. vue.createElementVNode("div", {
  5481. class: "my-cell flex",
  5482. onClick: _cache[2] || (_cache[2] = (...args) => $options.collapseTopReplyList && $options.collapseTopReplyList(...args))
  5483. }, [
  5484. _hoisted_29,
  5485. vue.createElementVNode("div", _hoisted_30, [
  5486. vue.createVNode(_component_Tooltip, { title: "收起高赞回复" }, {
  5487. default: vue.withCtx(() => [
  5488. vue.createElementVNode("div", _hoisted_31, [
  5489. vue.createVNode(_component_Icon, { icon: "gravity-ui:chevrons-collapse-vertical" })
  5490. ])
  5491. ]),
  5492. _: 1
  5493. })
  5494. ])
  5495. ]),
  5496. vue.createElementVNode("div", _hoisted_32, [
  5497. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.topReply, (item, index) => {
  5498. return vue.openBlock(), vue.createBlock(_component_Comment, {
  5499. key: item.floor,
  5500. type: "top",
  5501. modelValue: $options.topReply[index],
  5502. "onUpdate:modelValue": ($event) => $options.topReply[index] = $event
  5503. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  5504. }), 128))
  5505. ], 512)
  5506. ])) : vue.createCommentVNode("", true),
  5507. $options.isMobile ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_33, [
  5508. vue.createElementVNode("div", {
  5509. class: "inner",
  5510. innerHTML: $options.post.fr
  5511. }, null, 8, _hoisted_34)
  5512. ])) : vue.createCommentVNode("", true),
  5513. vue.createElementVNode("div", _hoisted_35, [
  5514. $options.post.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_36, [
  5515. vue.createElementVNode("div", null, [
  5516. vue.createTextVNode(vue.toDisplayString($options.post.replyCount) + " 条回复 ", 1),
  5517. $options.post.lastReplyDate ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_37, [
  5518. vue.createTextVNode("  "),
  5519. _hoisted_38,
  5520. vue.createTextVNode("  " + vue.toDisplayString($options.post.lastReplyDate), 1)
  5521. ])) : vue.createCommentVNode("", true)
  5522. ]),
  5523. $options.config.showToolbar ? (vue.openBlock(), vue.createBlock(_component_BaseSelect, {
  5524. key: 0,
  5525. "display-type": $props.displayType,
  5526. "onUpdate:displayType": _cache[3] || (_cache[3] = (e2) => _ctx.$emit("update:displayType", e2))
  5527. }, null, 8, ["display-type"])) : (vue.openBlock(), vue.createElementBlock("div", {
  5528. key: 1,
  5529. class: "fr",
  5530. innerHTML: $options.post.fr
  5531. }, null, 8, _hoisted_39))
  5532. ])) : vue.createCommentVNode("", true),
  5533. $options.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  5534. $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_40, [
  5535. vue.createVNode(_component_BaseLoading, { size: "large" })
  5536. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_41, [
  5537. $props.modelValue ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 0 }, vue.renderList($options.replyList, (item, index) => {
  5538. return vue.openBlock(), vue.createBlock(_component_Comment, {
  5539. key: item.floor,
  5540. modelValue: $options.replyList[index],
  5541. "onUpdate:modelValue": ($event) => $options.replyList[index] = $event
  5542. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  5543. }), 128)) : vue.createCommentVNode("", true)
  5544. ]))
  5545. ], 64)) : vue.createCommentVNode("", true)
  5546. ]),
  5547. !($options.replyList.length || $props.loading) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_42, "目前尚无回复")) : vue.createCommentVNode("", true),
  5548. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
  5549. key: 3,
  5550. class: vue.normalizeClass(["my-box", { "sticky": $data.isSticky }]),
  5551. ref: "replyBox"
  5552. }, [
  5553. vue.createElementVNode("div", _hoisted_43, [
  5554. _hoisted_44,
  5555. vue.createElementVNode("div", _hoisted_45, [
  5556. $data.isSticky ? (vue.openBlock(), vue.createElementBlock("a", {
  5557. key: 0,
  5558. style: { "margin-right": "2rem" },
  5559. onClick: _cache[4] || (_cache[4] = ($event) => $data.isSticky = false)
  5560. }, "取消回复框停靠")) : vue.createCommentVNode("", true),
  5561. vue.createElementVNode("a", {
  5562. onClick: _cache[5] || (_cache[5] = (...args) => $options.scrollTop && $options.scrollTop(...args))
  5563. }, "回到顶部")
  5564. ])
  5565. ]),
  5566. vue.createElementVNode("div", _hoisted_46, [
  5567. vue.createVNode(_component_PostEditor, {
  5568. onClose: $options.goBottom,
  5569. ref: "post-editor",
  5570. useType: "reply-post",
  5571. onClick: _cache[6] || (_cache[6] = ($event) => $data.isSticky = true)
  5572. }, null, 8, ["onClose"])
  5573. ])
  5574. ], 2)) : vue.createCommentVNode("", true)
  5575. ], 4),
  5576. $data.showRelationReply ? (vue.openBlock(), vue.createElementBlock("div", {
  5577. key: 0,
  5578. class: "relationReply",
  5579. onClick: _cache[10] || (_cache[10] = ($event) => $options.close("space"))
  5580. }, [
  5581. vue.createElementVNode("div", {
  5582. class: "my-cell flex",
  5583. onClick: _cache[8] || (_cache[8] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  5584. }, [
  5585. _hoisted_47,
  5586. vue.createElementVNode("div", _hoisted_48, [
  5587. vue.createVNode(_component_Icon, {
  5588. icon: "ic:round-close",
  5589. onClick: _cache[7] || (_cache[7] = ($event) => $data.showRelationReply = false)
  5590. })
  5591. ])
  5592. ]),
  5593. vue.createElementVNode("div", {
  5594. class: "comments",
  5595. onClick: _cache[9] || (_cache[9] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  5596. }, [
  5597. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.relationReply, (item, index) => {
  5598. return vue.openBlock(), vue.createBlock(_component_SingleComment, {
  5599. "is-right": item.username === $data.targetUser.right,
  5600. key: item.floor,
  5601. comment: item
  5602. }, null, 8, ["is-right", "comment"]);
  5603. }), 128))
  5604. ])
  5605. ])) : vue.createCommentVNode("", true),
  5606. $data.showCallList && $options.filterCallList.length ? (vue.openBlock(), vue.createElementBlock("div", {
  5607. key: 1,
  5608. class: "call-list",
  5609. style: vue.normalizeStyle($data.callStyle)
  5610. }, [
  5611. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.filterCallList, (item, index) => {
  5612. return vue.openBlock(), vue.createElementBlock("div", {
  5613. class: vue.normalizeClass(["call-item", { select: index === $data.selectCallIndex }]),
  5614. onClick: ($event) => $options.setCall(item)
  5615. }, [
  5616. vue.createElementVNode("a", null, vue.toDisplayString(item), 1)
  5617. ], 10, _hoisted_49);
  5618. }), 256))
  5619. ], 4)) : vue.createCommentVNode("", true),
  5620. vue.createElementVNode("div", {
  5621. class: "close-btn",
  5622. onClick: _cache[11] || (_cache[11] = ($event) => $options.close("btn"))
  5623. }, [
  5624. vue.createVNode(_component_Icon, { icon: "fontisto:close-a" })
  5625. ]),
  5626. vue.createElementVNode("div", {
  5627. class: "scroll-top gray",
  5628. onClick: _cache[12] || (_cache[12] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
  5629. }, [
  5630. vue.createVNode(_component_Icon, { icon: "lucide:move-up" })
  5631. ]),
  5632. vue.createElementVNode("div", {
  5633. class: "refresh gray",
  5634. onClick: _cache[13] || (_cache[13] = vue.withModifiers(($event) => _ctx.$emit("refresh"), ["stop"]))
  5635. }, [
  5636. $props.refreshLoading ? (vue.openBlock(), vue.createBlock(_component_BaseLoading, { key: 0 })) : (vue.openBlock(), vue.createBlock(_component_Icon, {
  5637. key: 1,
  5638. icon: "material-symbols:refresh"
  5639. }))
  5640. ]),
  5641. vue.createElementVNode("div", {
  5642. class: "scroll-to gray",
  5643. onClick: _cache[17] || (_cache[17] = vue.withModifiers(($event) => $options.jump($data.currentFloor), ["stop"]))
  5644. }, [
  5645. vue.createVNode(_component_Icon, { icon: "lucide:move-down" }),
  5646. vue.withDirectives(vue.createElementVNode("input", {
  5647. type: "text",
  5648. "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.currentFloor = $event),
  5649. onClick: _cache[15] || (_cache[15] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"])),
  5650. onKeydown: _cache[16] || (_cache[16] = vue.withKeys(($event) => $options.jump($data.currentFloor), ["enter"]))
  5651. }, null, 544), [
  5652. [vue.vModelText, $data.currentFloor]
  5653. ])
  5654. ])
  5655. ], 512)
  5656. ], 34)), [
  5657. [vue.vShow, $props.modelValue]
  5658. ]);
  5659. }
  5660. const PostDetail = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$2], ["__scopeId", "data-v-165fdc78"]]);
  5661. const _hoisted_1$5 = { key: 1 };
  5662. const _sfc_main$5 = {
  5663. __name: "Base64Tooltip",
  5664. setup(__props) {
  5665. const tooltip = vue.ref(null);
  5666. const show = vue.ref(false);
  5667. const originalText = vue.ref("");
  5668. const decodeText = vue.ref("");
  5669. const styleObject = vue.reactive({
  5670. left: "-100vw",
  5671. top: "-100vh"
  5672. });
  5673. vue.onMounted(() => {
  5674. eventBus.on(CMD.SHOW_TOOLTIP, ({ text, e: e2 }) => {
  5675. setTimeout(() => show.value = true);
  5676. originalText.value = text;
  5677. decodeText.value = "";
  5678. styleObject.left = e2.clientX + "px";
  5679. styleObject.top = e2.clientY + 20 + "px";
  5680. });
  5681. window.addEventListener("click", (e2) => {
  5682. if (!tooltip.value)
  5683. return;
  5684. if (!tooltip.value.contains(e2.target) && show.value) {
  5685. show.value = false;
  5686. }
  5687. }, { capture: true });
  5688. const fn = () => show.value && (show.value = false);
  5689. $(".post-detail", window.win().doc).on("scroll", fn);
  5690. });
  5691. function copy() {
  5692. if (window.win().navigator.clipboard) {
  5693. window.win().navigator.clipboard.writeText(decodeText.value);
  5694. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "复制成功" });
  5695. } else {
  5696. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "复制失败!浏览器不支持!" });
  5697. }
  5698. }
  5699. function base64ToArrayBuffer(base64) {
  5700. let binary_string = window.atob(base64);
  5701. let len = binary_string.length;
  5702. let bytes = new Uint8Array(len);
  5703. for (let i = 0; i < len; i++) {
  5704. bytes[i] = binary_string.charCodeAt(i);
  5705. }
  5706. return bytes.buffer;
  5707. }
  5708. function decode() {
  5709. try {
  5710. new Blob([base64ToArrayBuffer(originalText.value)]).text().then((r2) => {
  5711. decodeText.value = r2;
  5712. });
  5713. } catch (e2) {
  5714. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "Base64解码失败!不是标准数据!" });
  5715. }
  5716. }
  5717. return (_ctx, _cache) => {
  5718. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  5719. class: "base64_tooltip",
  5720. style: vue.normalizeStyle(styleObject),
  5721. onClick: decode,
  5722. ref_key: "tooltip",
  5723. ref: tooltip
  5724. }, [
  5725. !decodeText.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  5726. vue.createTextVNode(" Base64解码:" + vue.toDisplayString(originalText.value) + " ", 1),
  5727. vue.createVNode(vue.unref(Icon), { icon: "system-uicons:translate" })
  5728. ], 64)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$5, [
  5729. vue.createElementVNode("span", null, vue.toDisplayString(decodeText.value), 1),
  5730. vue.createVNode(BaseButton, {
  5731. class: "btn",
  5732. size: "small",
  5733. onClick: copy
  5734. }, {
  5735. default: vue.withCtx(() => [
  5736. vue.createTextVNode("点击复制")
  5737. ]),
  5738. _: 1
  5739. })
  5740. ]))
  5741. ], 4)), [
  5742. [vue.vShow, show.value]
  5743. ]);
  5744. };
  5745. }
  5746. };
  5747. const Base64Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-c50fb66c"]]);
  5748. const _sfc_main$4 = {
  5749. name: "Msg",
  5750. components: { Icon },
  5751. props: {
  5752. type: "",
  5753. text: ""
  5754. },
  5755. created() {
  5756. setTimeout(() => {
  5757. this.$emit("close");
  5758. }, 3e3);
  5759. }
  5760. };
  5761. const _hoisted_1$4 = { class: "right" };
  5762. function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
  5763. const _component_Icon = vue.resolveComponent("Icon");
  5764. return vue.openBlock(), vue.createElementBlock("div", {
  5765. class: vue.normalizeClass(["msg", $props.type])
  5766. }, [
  5767. vue.createElementVNode("div", {
  5768. class: "left",
  5769. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
  5770. }, [
  5771. vue.createVNode(_component_Icon, { icon: "ic:round-close" })
  5772. ]),
  5773. vue.createElementVNode("div", _hoisted_1$4, vue.toDisplayString($props.text), 1)
  5774. ], 2);
  5775. }
  5776. const Msg = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$1], ["__scopeId", "data-v-8bf692ea"]]);
  5777. const _withScopeId$2 = (n2) => (vue.pushScopeId("data-v-341122ff"), n2 = n2(), vue.popScopeId(), n2);
  5778. const _hoisted_1$3 = {
  5779. key: 0,
  5780. class: "tag-modal modal"
  5781. };
  5782. const _hoisted_2$2 = { class: "wrapper" };
  5783. const _hoisted_3$2 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 添加标签 ", -1));
  5784. const _hoisted_4$2 = { class: "option" };
  5785. const _hoisted_5$1 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户:", -1));
  5786. const _hoisted_6$1 = { class: "btns" };
  5787. const _sfc_main$3 = {
  5788. __name: "TagModal",
  5789. props: ["tags"],
  5790. emits: ["update:tags"],
  5791. setup(__props, { emit: __emit }) {
  5792. const tagModal = vue.reactive({
  5793. show: false,
  5794. currentUsername: "",
  5795. tag: ""
  5796. });
  5797. const props = __props;
  5798. const emit = __emit;
  5799. const inputRef = vue.ref();
  5800. vue.onMounted(() => {
  5801. eventBus.on(CMD.ADD_TAG, (username) => {
  5802. tagModal.currentUsername = username;
  5803. tagModal.show = true;
  5804. vue.nextTick(() => {
  5805. inputRef.value.focus();
  5806. });
  5807. });
  5808. });
  5809. async function addTag() {
  5810. if (!tagModal.tag) {
  5811. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请输入标签" });
  5812. return;
  5813. }
  5814. let oldTag = window.clone(props.tags);
  5815. let tempTag = window.clone(props.tags);
  5816. let userTags = tempTag[tagModal.currentUsername] ?? [];
  5817. let rIndex = userTags.findIndex((v) => v === tagModal.tag);
  5818. if (rIndex > -1) {
  5819. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "标签已存在!" });
  5820. return;
  5821. } else {
  5822. userTags.push(tagModal.tag);
  5823. }
  5824. tempTag[tagModal.currentUsername] = userTags;
  5825. emit("update:tags", tempTag);
  5826. tagModal.tag = "";
  5827. tagModal.show = false;
  5828. let res = await window.parse.saveTags(tempTag);
  5829. if (!res) {
  5830. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签添加失败!" });
  5831. emit("update:tags", oldTag);
  5832. }
  5833. }
  5834. return (_ctx, _cache) => {
  5835. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  5836. default: vue.withCtx(() => [
  5837. tagModal.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
  5838. vue.createElementVNode("div", {
  5839. class: "mask",
  5840. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => tagModal.show = false, ["stop"]))
  5841. }),
  5842. vue.createElementVNode("div", _hoisted_2$2, [
  5843. _hoisted_3$2,
  5844. vue.createElementVNode("div", _hoisted_4$2, [
  5845. _hoisted_5$1,
  5846. vue.createElementVNode("div", null, [
  5847. vue.createElementVNode("b", null, vue.toDisplayString(tagModal.currentUsername), 1)
  5848. ])
  5849. ]),
  5850. vue.withDirectives(vue.createElementVNode("input", {
  5851. type: "text",
  5852. ref_key: "inputRef",
  5853. ref: inputRef,
  5854. style: { "width": "100%" },
  5855. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tagModal.tag = $event),
  5856. onKeydown: vue.withKeys(addTag, ["enter"])
  5857. }, null, 544), [
  5858. [vue.vModelText, tagModal.tag]
  5859. ]),
  5860. vue.createElementVNode("div", _hoisted_6$1, [
  5861. vue.createVNode(BaseButton, {
  5862. type: "link",
  5863. onClick: _cache[2] || (_cache[2] = ($event) => {
  5864. tagModal.show = false;
  5865. tagModal.tag = "";
  5866. })
  5867. }, {
  5868. default: vue.withCtx(() => [
  5869. vue.createTextVNode("取消")
  5870. ]),
  5871. _: 1
  5872. }),
  5873. vue.createVNode(BaseButton, { onClick: addTag }, {
  5874. default: vue.withCtx(() => [
  5875. vue.createTextVNode("确定")
  5876. ]),
  5877. _: 1
  5878. })
  5879. ])
  5880. ])
  5881. ])) : vue.createCommentVNode("", true)
  5882. ]),
  5883. _: 1
  5884. });
  5885. };
  5886. }
  5887. };
  5888. const TagModal = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-341122ff"]]);
  5889. const _hoisted_1$2 = { class: "msgs" };
  5890. const _sfc_main$2 = {
  5891. __name: "MsgModal",
  5892. setup(__props) {
  5893. const msgList = vue.reactive([
  5894. // {type: 'success', text: '123', id: Date.now()}
  5895. ]);
  5896. vue.onMounted(() => {
  5897. eventBus.on(CMD.SHOW_MSG, (val) => {
  5898. msgList.push({ ...val, id: Date.now() });
  5899. });
  5900. });
  5901. function removeMsg(id) {
  5902. let rIndex = msgList.findIndex((item) => item.id === id);
  5903. if (rIndex > -1) {
  5904. msgList.splice(rIndex, 1);
  5905. }
  5906. }
  5907. return (_ctx, _cache) => {
  5908. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
  5909. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(msgList, (v) => {
  5910. return vue.openBlock(), vue.createBlock(Msg, {
  5911. key: v.id,
  5912. type: v.type,
  5913. text: v.text,
  5914. onClose: ($event) => removeMsg(v.id)
  5915. }, null, 8, ["type", "text", "onClose"]);
  5916. }), 128))
  5917. ]);
  5918. };
  5919. }
  5920. };
  5921. const MsgModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b73f4332"]]);
  5922. let u = ".__cf_email__", f = "data-cfemail", d = document.createElement("div");
  5923. function e(e2) {
  5924. console.error(e2);
  5925. }
  5926. function r(e2, t) {
  5927. let r2 = e2.substr(t, 2);
  5928. return parseInt(r2, 16);
  5929. }
  5930. function n(href, index) {
  5931. let o = "", a = r(href, index);
  5932. for (let i = index + 2; i < href.length; i += 2) {
  5933. let l = r(href, i) ^ a;
  5934. o += String.fromCharCode(l);
  5935. }
  5936. try {
  5937. o = decodeURIComponent(escape(o));
  5938. } catch (u2) {
  5939. e(u2);
  5940. }
  5941. d.innerHTML = '<a href="' + o.replace(/"/g, "&quot;") + '"></a>';
  5942. return d.childNodes[0].getAttribute("href") || "";
  5943. }
  5944. function decodeEmail(body) {
  5945. try {
  5946. let as = body.find(u);
  5947. as.each(function() {
  5948. try {
  5949. let o = this, a = o.parentNode, i = o.getAttribute(f);
  5950. if (i) {
  5951. let l = n(i, 0), d2 = document.createTextNode(l);
  5952. a.replaceChild(d2, o);
  5953. }
  5954. } catch (h2) {
  5955. e(h2);
  5956. }
  5957. });
  5958. } catch (s) {
  5959. e(s);
  5960. }
  5961. }
  5962. const _withScopeId$1 = (n2) => (vue.pushScopeId("data-v-882b932b"), n2 = n2(), vue.popScopeId(), n2);
  5963. const _hoisted_1$1 = {
  5964. key: 0,
  5965. class: "tag-modal modal"
  5966. };
  5967. const _hoisted_2$1 = { class: "modal-root" };
  5968. const _hoisted_3$1 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 提醒系统 ", -1));
  5969. const _hoisted_4$1 = ["innerHTML"];
  5970. const _sfc_main$1 = {
  5971. __name: "NotificationModal",
  5972. props: ["modelValue", "h"],
  5973. emits: ["update:modelValue"],
  5974. setup(__props, { emit: __emit }) {
  5975. const emit = __emit;
  5976. vue.onMounted(() => {
  5977. });
  5978. function close() {
  5979. emit("update:modelValue", false);
  5980. }
  5981. return (_ctx, _cache) => {
  5982. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  5983. default: vue.withCtx(() => [
  5984. __props.modelValue ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
  5985. vue.createElementVNode("div", {
  5986. class: "mask",
  5987. onClick: vue.withModifiers(close, ["stop"])
  5988. }),
  5989. vue.createElementVNode("div", _hoisted_2$1, [
  5990. vue.createElementVNode("div", { class: "modal-header" }, [
  5991. _hoisted_3$1,
  5992. vue.createElementVNode("i", {
  5993. class: "fa fa-times",
  5994. onClick: close
  5995. })
  5996. ]),
  5997. vue.createElementVNode("div", {
  5998. innerHTML: __props.h,
  5999. class: "modal-body"
  6000. }, null, 8, _hoisted_4$1)
  6001. ])
  6002. ])) : vue.createCommentVNode("", true)
  6003. ]),
  6004. _: 1
  6005. });
  6006. };
  6007. }
  6008. };
  6009. const NotificationModal = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-882b932b"]]);
  6010. const _sfc_main = {
  6011. components: {
  6012. BaseButton,
  6013. NotificationModal,
  6014. BaseLoading,
  6015. BaseSwitch,
  6016. MsgModal,
  6017. TagModal,
  6018. Tooltip,
  6019. Setting,
  6020. PostDetail,
  6021. Base64Tooltip,
  6022. Msg
  6023. },
  6024. provide() {
  6025. return {
  6026. isMobile: vue.computed(() => window.vals.isMobile),
  6027. isLogin: vue.computed(() => this.isLogin),
  6028. isNight: vue.computed(() => this.isNight),
  6029. pageType: vue.computed(() => this.pageType),
  6030. tags: vue.computed(() => this.tags),
  6031. show: vue.computed(() => this.show),
  6032. post: vue.computed(() => this.current),
  6033. config: vue.computed(() => this.config),
  6034. allReplyUsers: vue.computed(() => {
  6035. var _a, _b, _c;
  6036. if ((_a = this.current) == null ? void 0 : _a.replyList) {
  6037. return Array.from(new Set(((_c = (_b = this.current) == null ? void 0 : _b.replyList) == null ? void 0 : _c.map((v) => v.username)) ?? []));
  6038. }
  6039. return [];
  6040. }),
  6041. showConfig: this.showConfig
  6042. };
  6043. },
  6044. data() {
  6045. return {
  6046. loading: window.pageType === PageType.Post,
  6047. refreshLoading: false,
  6048. loadMore: false,
  6049. isLogin: !!window.user.username,
  6050. pageType: window.pageType,
  6051. isNight: window.isNight,
  6052. stopMe: window.stopMe,
  6053. //停止使用脚本
  6054. show: false,
  6055. current: window.clone(window.initPost),
  6056. list: [],
  6057. config: window.clone(window.config),
  6058. tags: window.user.tags,
  6059. configModal: {
  6060. show: false
  6061. },
  6062. notificationModal: {
  6063. show: false,
  6064. h: ""
  6065. }
  6066. };
  6067. },
  6068. computed: {
  6069. targetUserTags() {
  6070. return this.tags[window.targetUserName] ?? [];
  6071. },
  6072. isList() {
  6073. return [PageType.Home, PageType.Node].includes(this.pageType);
  6074. },
  6075. isPost() {
  6076. return this.pageType === PageType.Post;
  6077. },
  6078. isMember() {
  6079. return this.pageType === PageType.Member;
  6080. }
  6081. },
  6082. watch: {
  6083. config: {
  6084. handler(newVal) {
  6085. let config2 = { [window.user.username ?? "default"]: newVal };
  6086. localStorage.setItem("v2ex-config", JSON.stringify(config2));
  6087. window.config = newVal;
  6088. },
  6089. deep: true
  6090. },
  6091. tags(newVal) {
  6092. window.user.tags = newVal;
  6093. },
  6094. "config.viewType"(newVal) {
  6095. if (!newVal)
  6096. return;
  6097. if (newVal === "card") {
  6098. $(".post-item").each(function() {
  6099. $(this).addClass("preview");
  6100. });
  6101. } else {
  6102. $(".post-item").each(function() {
  6103. $(this).removeClass("preview");
  6104. });
  6105. }
  6106. }
  6107. },
  6108. created() {
  6109. let that = this;
  6110. this.initEvent();
  6111. window.cb = this.winCb;
  6112. if (!window.canParseV2exPage)
  6113. return;
  6114. $(document).on("click", "a", this.clickA);
  6115. $(document).on("click", ".post-item", function(e2) {
  6116. if (e2.currentTarget.getAttribute("script"))
  6117. return;
  6118. if (that.stopMe)
  6119. return true;
  6120. if (this.classList.contains("preview")) {
  6121. if (e2.target.tagName !== "A" && e2.target.tagName !== "IMG" && !e2.target.classList.contains("toggle")) {
  6122. console.log("点空白处", this);
  6123. let id = this.dataset["id"];
  6124. let href = this.dataset["href"];
  6125. if (id) {
  6126. that.clickPost(e2, id, href);
  6127. } else {
  6128. if (href)
  6129. location.href = href;
  6130. }
  6131. }
  6132. }
  6133. });
  6134. $(document).on("click", ".toggle", (e2) => {
  6135. if (this.stopMe)
  6136. return true;
  6137. let id = e2.target.dataset["id"];
  6138. let itemDom = document.querySelector(`.id_${id}`);
  6139. if (itemDom.classList.contains("preview")) {
  6140. e2.target.innerText = "预览";
  6141. itemDom.classList.remove("preview");
  6142. } else {
  6143. if (this.config.viewType !== "card") {
  6144. let index = this.list.findIndex((v) => v.id == id);
  6145. if (index > -1) {
  6146. e2.target.innerText = "收起";
  6147. itemDom.classList.add("preview");
  6148. } else {
  6149. e2.target.innerText = "加载中";
  6150. functions.getPostDetailByApi(id).then((res) => {
  6151. if (res.content_rendered) {
  6152. res.href = itemDom.dataset["href"];
  6153. this.list.push(getDefaultPost(res));
  6154. itemDom.classList.add("preview");
  6155. e2.target.innerText = "收起";
  6156. functions.appendPostContent(res, itemDom);
  6157. } else {
  6158. e2.target.innerText = "预览";
  6159. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "主题暂无正文!" });
  6160. }
  6161. });
  6162. }
  6163. } else {
  6164. e2.target.innerText = "收起";
  6165. itemDom.classList.add("preview");
  6166. }
  6167. }
  6168. });
  6169. window.onpopstate = (event) => {
  6170. if (event.state) {
  6171. if (!this.show)
  6172. this.show = true;
  6173. } else {
  6174. if (this.show)
  6175. this.show = false;
  6176. }
  6177. };
  6178. window.deleteNotification = (nId, token) => {
  6179. console.log("deleteNotification", nId, token);
  6180. let item = $("#n_" + nId);
  6181. item.slideUp("fast");
  6182. $.post({
  6183. url: "/delete/notification/" + nId + "?once=" + token,
  6184. success() {
  6185. $.get({
  6186. url: "/notifications/below/" + window.notificationBottom,
  6187. success(data, status, request) {
  6188. item.remove();
  6189. $("#notifications").append(data);
  6190. window.notificationBottom = request.getResponseHeader("X-V2EX-New-Notification-Bottom");
  6191. },
  6192. error() {
  6193. item.slideDown("fast");
  6194. }
  6195. });
  6196. },
  6197. error() {
  6198. item.slideDown("fast");
  6199. }
  6200. });
  6201. };
  6202. },
  6203. beforeUnmount() {
  6204. eventBus.clear();
  6205. $(document).off("click", "a", this.clickA);
  6206. },
  6207. methods: {
  6208. async getUnreadMessagesCount() {
  6209. var _a, _b;
  6210. const res = await fetch(`${location.origin}/mission`);
  6211. const htmlText = await res.text();
  6212. const $page = $(htmlText);
  6213. const text = $page.find('#Rightbar a[href^="/notifications"]').text();
  6214. if (text.includes("未读提醒")) {
  6215. const countStr = (_a = text.match(/\d+/)) == null ? void 0 : _a.at(0);
  6216. if (countStr) {
  6217. return Number((_b = text.match(/\d+/)) == null ? void 0 : _b.at(0));
  6218. }
  6219. } else {
  6220. return 0;
  6221. }
  6222. throw new Error("无法获取未读消息数量");
  6223. },
  6224. clickA(e2) {
  6225. let that = this;
  6226. if (e2.currentTarget.getAttribute("script"))
  6227. return;
  6228. if (that.stopMe)
  6229. return true;
  6230. let { pageType } = functions.checkPageType(e2.currentTarget);
  6231. switch (pageType) {
  6232. case PageType.Post:
  6233. let { href, id, title } = functions.parseA(e2.currentTarget);
  6234. if (id) {
  6235. that.clickPost(e2, id, href, title);
  6236. }
  6237. break;
  6238. case PageType.Node:
  6239. case PageType.Home:
  6240. case PageType.Changes:
  6241. return;
  6242. default:
  6243. if (e2.currentTarget.href.includes("/settings/night/toggle"))
  6244. return;
  6245. if (e2.currentTarget.href === location.origin + "/#;")
  6246. return;
  6247. if (e2.currentTarget.href.includes("/notifications"))
  6248. ;
  6249. if (that.config.newTabOpen) {
  6250. that.stopEvent(e2);
  6251. functions.openNewTab(e2.currentTarget.href, that.config.newTabOpenActive);
  6252. }
  6253. return;
  6254. }
  6255. },
  6256. stopEvent(e2) {
  6257. e2.preventDefault();
  6258. e2.stopPropagation();
  6259. },
  6260. async clickPost(e2, id, href, title = "") {
  6261. if (id) {
  6262. if (this.config.clickPostItemOpenDetail) {
  6263. this.stopEvent(e2);
  6264. let postItem = getDefaultPost();
  6265. let index = this.list.findIndex((v) => v.id == id);
  6266. if (index > -1) {
  6267. postItem = this.list[index];
  6268. }
  6269. if (!postItem.title)
  6270. postItem.title = title ?? "加载中";
  6271. postItem.id = id;
  6272. postItem.href = href;
  6273. this.getPostDetail(postItem);
  6274. return;
  6275. }
  6276. if (this.config.newTabOpen) {
  6277. this.stopEvent(e2);
  6278. functions.openNewTab(`https://www.v2ex.com/t/${id}?p=1`, this.config.newTabOpenActive);
  6279. }
  6280. }
  6281. },
  6282. showPost() {
  6283. this.show = true;
  6284. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  6285. $(this).hide();
  6286. });
  6287. },
  6288. showConfig() {
  6289. this.configModal.show = true;
  6290. },
  6291. async winCb({ type, value }) {
  6292. console.log("回调的类型", type, value);
  6293. if (type === "openSetting") {
  6294. this.showConfig();
  6295. }
  6296. if (type === "syncData") {
  6297. this.list = Object.assign(this.list, window.postList);
  6298. this.config = window.config;
  6299. this.stopMe = window.stopMe;
  6300. this.tags = window.user.tags;
  6301. }
  6302. if (type === "warningNotice") {
  6303. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: value });
  6304. }
  6305. if (this.stopMe)
  6306. return;
  6307. if (type === "restorePost") {
  6308. this.show = false;
  6309. this.loading = false;
  6310. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "脚本无法查看此页面!" });
  6311. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  6312. $(this).show();
  6313. });
  6314. }
  6315. if (type === "postContent") {
  6316. this.current = Object.assign(this.current, value);
  6317. this.current.inList = true;
  6318. if (this.config.autoOpenDetail) {
  6319. this.showPost();
  6320. }
  6321. }
  6322. if (type === "postReplies") {
  6323. this.current = Object.assign(this.current, value);
  6324. this.list.push(this.clone(this.current));
  6325. this.loading = false;
  6326. }
  6327. },
  6328. clone(val) {
  6329. return window.clone(val);
  6330. },
  6331. regenerateReplyList() {
  6332. if (this.current.replyList.length) {
  6333. this.current.replyCount = this.current.replyList.length;
  6334. let res = functions.createNestedList(this.current.replyList);
  6335. if (res) {
  6336. this.current.nestedReplies = res;
  6337. }
  6338. let dup_res = functions.createNestedRedundantList(this.current.replyList);
  6339. if (dup_res) {
  6340. this.current.nestedRedundReplies = dup_res;
  6341. }
  6342. } else {
  6343. this.current.replyCount = 0;
  6344. this.current.nestedReplies = [];
  6345. this.current.nestedRedundReplies = [];
  6346. }
  6347. if (this.list.length) {
  6348. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  6349. if (rIndex > -1) {
  6350. this.list[rIndex] = this.clone(this.current);
  6351. }
  6352. }
  6353. },
  6354. initEvent() {
  6355. eventBus.on(CMD.CHANGE_COMMENT_THANK, (val) => {
  6356. console.log("CHANGE_COMMENT_THANK", val);
  6357. const { id, type } = val;
  6358. let currentI = this.current.replyList.findIndex((i) => i.id === id);
  6359. if (currentI > -1) {
  6360. this.current.replyList[currentI].isThanked = type === "add";
  6361. if (type === "add") {
  6362. this.current.replyList[currentI].thankCount++;
  6363. } else {
  6364. this.current.replyList[currentI].thankCount--;
  6365. }
  6366. this.regenerateReplyList();
  6367. }
  6368. });
  6369. eventBus.on(CMD.CHANGE_POST_THANK, (val) => {
  6370. const { id, type } = val;
  6371. this.current.isThanked = type === "add";
  6372. if (type === "add") {
  6373. this.current.thankCount++;
  6374. } else {
  6375. this.current.thankCount--;
  6376. }
  6377. let currentI = this.list.findIndex((i) => i.id === id);
  6378. if (currentI > -1) {
  6379. this.list[currentI].isThanked = type === "add";
  6380. if (type === "add") {
  6381. this.list[currentI].thankCount++;
  6382. } else {
  6383. this.list[currentI].thankCount++;
  6384. }
  6385. }
  6386. });
  6387. eventBus.on(CMD.REMOVE, (val) => {
  6388. let removeIndex = this.current.replyList.findIndex((i) => i.floor === val);
  6389. if (removeIndex > -1) {
  6390. this.current.replyList.splice(removeIndex, 1);
  6391. }
  6392. this.regenerateReplyList();
  6393. });
  6394. eventBus.on(CMD.IGNORE, () => {
  6395. this.show = false;
  6396. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  6397. if (rIndex > -1) {
  6398. this.list.splice(rIndex, 1);
  6399. }
  6400. this.current = this.clone(window.initPost);
  6401. });
  6402. eventBus.on(CMD.MERGE, (val) => {
  6403. this.current = Object.assign(this.current, val);
  6404. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  6405. if (rIndex > -1) {
  6406. this.list[rIndex] = this.clone(this.current);
  6407. }
  6408. });
  6409. eventBus.on(CMD.ADD_REPLY, (item) => {
  6410. this.current.replyList.push(item);
  6411. this.regenerateReplyList();
  6412. });
  6413. eventBus.on(CMD.REFRESH_ONCE, async (once) => {
  6414. if (once) {
  6415. if (typeof once === "string") {
  6416. let res = once.match(/var once = "([\d]+)";/);
  6417. if (res && res[1]) {
  6418. this.current.once = Number(res[1]);
  6419. return;
  6420. }
  6421. }
  6422. if (typeof once === "number") {
  6423. this.current.once = once;
  6424. return;
  6425. }
  6426. }
  6427. window.fetchOnce().then((r2) => {
  6428. this.current.once = r2;
  6429. });
  6430. });
  6431. eventBus.on(CMD.REMOVE_TAG, async ({ username, tag }) => {
  6432. let oldTag = this.clone(this.tags);
  6433. let tags = this.tags[username] ?? [];
  6434. let rIndex = tags.findIndex((v) => v === tag);
  6435. if (rIndex > -1) {
  6436. tags.splice(rIndex, 1);
  6437. }
  6438. this.tags[username] = tags;
  6439. let res = await window.parse.saveTags(this.tags);
  6440. if (!res) {
  6441. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签删除失败!" });
  6442. this.tags = oldTag;
  6443. }
  6444. });
  6445. eventBus.on(CMD.REFRESH_POST, () => this.getPostDetail(this.current));
  6446. },
  6447. async getPostDetail(post) {
  6448. this.current = post;
  6449. this.show = true;
  6450. let url = window.baseUrl + "/t/" + this.current.id;
  6451. this.current.url = url;
  6452. let alreadyHasReply = this.current.replyList.length;
  6453. if (alreadyHasReply) {
  6454. this.refreshLoading = true;
  6455. } else {
  6456. this.loading = true;
  6457. functions.getPostDetailByApi(this.current.id).then((d2) => {
  6458. d2.replyCount = d2.replies;
  6459. this.current = Object.assign(this.current, d2);
  6460. if (this.current.replyCount > MAX_REPLY_LIMIT) {
  6461. functions.openNewTab(`${location.origin}/t/${this.current.id}?p=1&script=1`, true);
  6462. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "由于回复数量较多,已为您单独打开此主题" });
  6463. this.loading = this.show = false;
  6464. return;
  6465. } else {
  6466. this.current.jsonContent = `
  6467. <div class="cell">
  6468. <div class="topic_content">
  6469. <div class="markdown_body">
  6470. ${(d2 == null ? void 0 : d2.content_rendered) ?? ""}
  6471. </div>
  6472. </div>
  6473. </div>`;
  6474. }
  6475. });
  6476. }
  6477. let apiRes = await window.fetch(url + "?p=1");
  6478. if (apiRes.status === 404) {
  6479. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "主题未找到" });
  6480. return this.refreshLoading = this.loading = false;
  6481. }
  6482. if (apiRes.status === 403) {
  6483. this.refreshLoading = this.show = this.loading = false;
  6484. functions.openNewTab(`${location.origin}/t/${post.id}?p=1&script=0`, true);
  6485. return;
  6486. }
  6487. if (apiRes.redirected) {
  6488. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有权限" });
  6489. return this.refreshLoading = this.loading = false;
  6490. }
  6491. let htmlText = await apiRes.text();
  6492. let hasPermission = htmlText.search("你要查看的页面需要先登录");
  6493. if (hasPermission > -1) {
  6494. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你要查看的页面需要先登录" });
  6495. return this.refreshLoading = this.loading = false;
  6496. }
  6497. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  6498. let body = $(bodyText[0]);
  6499. decodeEmail(body);
  6500. await window.parse.getPostDetail(this.current, body, htmlText);
  6501. let index = this.list.findIndex((v) => v.id == this.current.id);
  6502. if (index > -1) {
  6503. this.list[index] = this.clone(this.current);
  6504. } else {
  6505. this.list.push(this.clone(this.current));
  6506. }
  6507. this.refreshLoading = this.loading = false;
  6508. await window.parse.parseOp(this.current);
  6509. console.log("当前主题", this.current);
  6510. },
  6511. addTargetUserTag() {
  6512. eventBus.emit(CMD.ADD_TAG, window.targetUserName);
  6513. },
  6514. removeTargetUserTag(tag) {
  6515. eventBus.emit(CMD.REMOVE_TAG, { username: window.targetUserName, tag });
  6516. }
  6517. }
  6518. };
  6519. const _withScopeId = (n2) => (vue.pushScopeId("data-v-38726989"), n2 = n2(), vue.popScopeId(), n2);
  6520. const _hoisted_1 = {
  6521. key: 0,
  6522. class: "target-user-tags p1"
  6523. };
  6524. const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "标签:", -1));
  6525. const _hoisted_3 = { class: "my-tag" };
  6526. const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  6527. const _hoisted_5 = ["onClick"];
  6528. const _hoisted_6 = {
  6529. key: 1,
  6530. class: "my-box p2",
  6531. style: { "margin-top": "2rem", "margin-bottom": "0" }
  6532. };
  6533. const _hoisted_7 = {
  6534. key: 0,
  6535. class: "flex flex-center"
  6536. };
  6537. const _hoisted_8 = {
  6538. key: 1,
  6539. class: "loaded"
  6540. };
  6541. const _hoisted_9 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "楼中楼解析完成", -1));
  6542. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  6543. const _component_Setting = vue.resolveComponent("Setting");
  6544. const _component_TagModal = vue.resolveComponent("TagModal");
  6545. const _component_PostDetail = vue.resolveComponent("PostDetail");
  6546. const _component_Base64Tooltip = vue.resolveComponent("Base64Tooltip");
  6547. const _component_MsgModal = vue.resolveComponent("MsgModal");
  6548. const _component_NotificationModal = vue.resolveComponent("NotificationModal");
  6549. const _component_BaseLoading = vue.resolveComponent("BaseLoading");
  6550. const _component_BaseButton = vue.resolveComponent("BaseButton");
  6551. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  6552. vue.createVNode(_component_Setting, {
  6553. modelValue: $data.config,
  6554. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.config = $event),
  6555. show: $data.configModal.show,
  6556. "onUpdate:show": _cache[1] || (_cache[1] = ($event) => $data.configModal.show = $event)
  6557. }, null, 8, ["modelValue", "show"]),
  6558. vue.createVNode(_component_TagModal, {
  6559. tags: $data.tags,
  6560. "onUpdate:tags": _cache[2] || (_cache[2] = ($event) => $data.tags = $event)
  6561. }, null, 8, ["tags"]),
  6562. vue.createVNode(_component_PostDetail, {
  6563. modelValue: $data.show,
  6564. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.show = $event),
  6565. ref: "postDetail",
  6566. displayType: $data.config.commentDisplayType,
  6567. "onUpdate:displayType": _cache[4] || (_cache[4] = ($event) => $data.config.commentDisplayType = $event),
  6568. onRefresh: _cache[5] || (_cache[5] = ($event) => $options.getPostDetail($data.current)),
  6569. loading: $data.loading,
  6570. refreshLoading: $data.refreshLoading
  6571. }, null, 8, ["modelValue", "displayType", "loading", "refreshLoading"]),
  6572. vue.createVNode(_component_Base64Tooltip),
  6573. vue.createVNode(_component_MsgModal),
  6574. vue.createVNode(_component_NotificationModal, {
  6575. modelValue: $data.notificationModal.show,
  6576. "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => $data.notificationModal.show = $event),
  6577. h: $data.notificationModal.h
  6578. }, null, 8, ["modelValue", "h"]),
  6579. !$data.stopMe ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  6580. $options.isMember && $data.isLogin && $data.config.openTag ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
  6581. _hoisted_2,
  6582. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.targetUserTags, (i) => {
  6583. return vue.openBlock(), vue.createElementBlock("span", _hoisted_3, [
  6584. _hoisted_4,
  6585. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  6586. vue.createElementVNode("i", {
  6587. class: "fa fa-trash-o remove",
  6588. onClick: ($event) => $options.removeTargetUserTag(i)
  6589. }, null, 8, _hoisted_5)
  6590. ]);
  6591. }), 256)),
  6592. vue.createElementVNode("span", {
  6593. class: "add-tag ago",
  6594. onClick: _cache[7] || (_cache[7] = (...args) => $options.addTargetUserTag && $options.addTargetUserTag(...args)),
  6595. title: "添加标签"
  6596. }, "+")
  6597. ])) : vue.createCommentVNode("", true),
  6598. $options.isPost && !$data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6, [
  6599. $data.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [
  6600. vue.createVNode(_component_BaseLoading)
  6601. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_8, [
  6602. _hoisted_9,
  6603. vue.createVNode(_component_BaseButton, {
  6604. size: "small",
  6605. onClick: $options.showPost
  6606. }, {
  6607. default: vue.withCtx(() => [
  6608. vue.createTextVNode("点击显示")
  6609. ]),
  6610. _: 1
  6611. }, 8, ["onClick"])
  6612. ]))
  6613. ])) : vue.createCommentVNode("", true)
  6614. ], 64)) : vue.createCommentVNode("", true)
  6615. ], 64);
  6616. }
  6617. const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-38726989"]]);
  6618. let isMobile = !document.querySelector("#Rightbar");
  6619. let $section = document.createElement("section");
  6620. $section.id = "app";
  6621. function run() {
  6622. window.baseUrl = location.origin;
  6623. window.initPost = DefaultPost;
  6624. window.win = function() {
  6625. return window;
  6626. };
  6627. window.win().doc = window.win().document;
  6628. window.win().query = (v) => window.win().document.querySelector(v);
  6629. window.query = (v) => window.win().document.querySelector(v);
  6630. window.clone = (val) => JSON.parse(JSON.stringify(val));
  6631. window.user = DefaultUser;
  6632. window.targetUserName = "";
  6633. window.pageType = void 0;
  6634. window.pageData = { pageNo: 1 };
  6635. window.config = DefaultConfig;
  6636. window.isNight = $(".Night").length === 1;
  6637. window.cb = null;
  6638. window.stopMe = false;
  6639. window.postList = [];
  6640. window.parse = {
  6641. //解析主题内容
  6642. async parsePostContent(post, body, htmlText) {
  6643. let once = htmlText.match(/var once = "([\d]+)";/);
  6644. if (once && once[1]) {
  6645. post.once = once[1];
  6646. }
  6647. post.isReport = htmlText.includes("你已对本主题进行了报告");
  6648. let wrapper = body.find("#Main");
  6649. if (!post.title || !post.content_rendered) {
  6650. let h1 = wrapper.find("h1");
  6651. if (h1) {
  6652. post.title = h1[0].innerText;
  6653. }
  6654. }
  6655. let as = wrapper.find(".header > a");
  6656. if (as.length) {
  6657. post.node.title = as[1].innerText;
  6658. post.node.url = as[1].href;
  6659. }
  6660. let aName = wrapper.find(".header small.gray a:nth-child(1)");
  6661. if (aName.length) {
  6662. post.member.username = aName[0].innerText;
  6663. }
  6664. let spanEl = wrapper.find(".header small.gray span");
  6665. if (spanEl.length) {
  6666. post.createDateAgo = spanEl[0].innerText;
  6667. post.createDate = spanEl[0].title;
  6668. }
  6669. let avatarEl = wrapper.find(".header .avatar");
  6670. if (avatarEl.length) {
  6671. post.member.avatar_large = avatarEl[0].src;
  6672. }
  6673. let topic_buttons = body.find(".topic_buttons");
  6674. if (topic_buttons.length) {
  6675. let favoriteNode = topic_buttons.find(".tb:first");
  6676. if (favoriteNode.length) {
  6677. post.isFavorite = favoriteNode[0].innerText === "取消收藏";
  6678. }
  6679. let ignoreNode = topic_buttons.find(".tb:nth-child(3)");
  6680. if (ignoreNode.length) {
  6681. post.isIgnore = ignoreNode[0].innerText === "取消忽略";
  6682. }
  6683. let thankNode = topic_buttons.find("#topic_thank .tb");
  6684. if (!thankNode.length) {
  6685. post.isThanked = true;
  6686. }
  6687. let topic_stats = topic_buttons.find(".topic_stats");
  6688. if (topic_stats.length) {
  6689. let text = topic_stats[0].innerText;
  6690. let reg1 = text.matchAll(/([\d]+)[\s]*人收藏/g);
  6691. let collectCountReg = [...reg1];
  6692. if (collectCountReg.length) {
  6693. post.collectCount = Number(collectCountReg[0][1]);
  6694. }
  6695. reg1 = text.matchAll(/([\d]+)[\s]*likes/g);
  6696. collectCountReg = [...reg1];
  6697. if (collectCountReg.length) {
  6698. post.collectCount = Number(collectCountReg[0][1]);
  6699. }
  6700. let reg2 = text.matchAll(/([\d]+)[\s]*人感谢/g);
  6701. let thankCountReg = [...reg2];
  6702. if (thankCountReg.length) {
  6703. post.thankCount = Number(thankCountReg[0][1]);
  6704. }
  6705. let reg3 = text.matchAll(/([\d]+)[\s]*次点击/g);
  6706. let clickCountReg = [...reg3];
  6707. if (clickCountReg.length) {
  6708. post.clickCount = Number(clickCountReg[0][1]);
  6709. }
  6710. reg3 = text.matchAll(/([\d]+)[\s]*views/g);
  6711. clickCountReg = [...reg3];
  6712. if (clickCountReg.length) {
  6713. post.clickCount = Number(clickCountReg[0][1]);
  6714. }
  6715. }
  6716. }
  6717. let header = body.find(`#Main .box`).first();
  6718. let temp = header.clone();
  6719. temp.find(".topic_buttons").remove();
  6720. temp.find(".inner").remove();
  6721. temp.find(".header").remove();
  6722. let html = temp.html();
  6723. html = functions.checkPhotoLink2Img(html);
  6724. post.headerTemplate = html;
  6725. return post;
  6726. },
  6727. //解析OP信息
  6728. async parseOp(post) {
  6729. if (!post.member.id) {
  6730. let userRes = await fetch(window.baseUrl + "/api/members/show.json?username=" + post.member.username);
  6731. if (userRes.status === 200) {
  6732. post.member = await userRes.json();
  6733. }
  6734. }
  6735. if (post.member.id) {
  6736. let date = new Date(post.member.created * 1e3);
  6737. let createStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
  6738. date.setHours(0);
  6739. date.setMinutes(0);
  6740. date.setSeconds(0);
  6741. date.setMilliseconds(0);
  6742. let now = /* @__PURE__ */ new Date();
  6743. now.setHours(0);
  6744. now.setMinutes(0);
  6745. now.setSeconds(0);
  6746. now.setMilliseconds(0);
  6747. let d2 = now.getTime() - date.getTime();
  6748. let isNew = d2 <= 1e3 * 60 * 60 * 24 * 7;
  6749. post.member.createDate = createStr + " 注册";
  6750. post.member.isNew = isNew;
  6751. } else {
  6752. post.member.createDate = "用户已被注销/封禁";
  6753. post.member.isNew = true;
  6754. }
  6755. return post;
  6756. },
  6757. //获取主题所有回复
  6758. async getPostAllReplies(post, body, htmlText, pageNo = 1) {
  6759. var _a, _b;
  6760. if (body.find("#no-comments-yet").length) {
  6761. return post;
  6762. }
  6763. let boxs = body.find(`#Main .box`);
  6764. let box = boxs[1];
  6765. let cells = box.querySelectorAll(".cell");
  6766. if (cells && cells.length) {
  6767. post.fr = cells[0].querySelector(".cell .fr").innerHTML;
  6768. cells = Array.from(cells);
  6769. let snow = cells[0].querySelector(".snow");
  6770. post.lastReplyDate = ((_b = (_a = snow == null ? void 0 : snow.nextSibling) == null ? void 0 : _a.nodeValue) == null ? void 0 : _b.trim()) || "";
  6771. let repliesMap = [];
  6772. if (cells[1].id) {
  6773. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(1)) });
  6774. let replyList = functions.getAllReply(repliesMap);
  6775. post.replyList = replyList;
  6776. post.replyCount = replyList.length;
  6777. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  6778. let nestedList = functions.createNestedList(replyList);
  6779. let nestedRedundantList = functions.createNestedRedundantList(replyList);
  6780. if (nestedList)
  6781. post.nestedReplies = nestedList;
  6782. if (nestedRedundantList)
  6783. post.nestedRedundReplies = nestedRedundantList;
  6784. return post;
  6785. } else {
  6786. let promiseList = [];
  6787. return new Promise((resolve, reject) => {
  6788. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  6789. let pages = cells[1].querySelectorAll("a.page_normal");
  6790. pages = Array.from(pages);
  6791. let url = window.baseUrl + "/t/" + post.id;
  6792. for (let i = 0; i < pages.length; i++) {
  6793. let currentPageNo = Number(pages[i].innerText);
  6794. promiseList.push(this.fetchPostOtherPageReplies(url + "?p=" + currentPageNo, currentPageNo));
  6795. }
  6796. Promise.allSettled(promiseList).then(
  6797. (results) => {
  6798. results.filter((result) => result.status === "fulfilled").map((v) => repliesMap.push(v.value));
  6799. let replyList = functions.getAllReply(repliesMap);
  6800. post.replyList = replyList;
  6801. post.replyCount = replyList.length;
  6802. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  6803. let nestedList = functions.createNestedList(replyList);
  6804. let nestedRedundantList = functions.createNestedRedundantList(replyList);
  6805. if (nestedList)
  6806. post.nestedReplies = nestedList;
  6807. if (nestedRedundantList)
  6808. post.nestedRedundReplies = nestedRedundantList;
  6809. resolve(post);
  6810. }
  6811. );
  6812. });
  6813. }
  6814. }
  6815. },
  6816. //请求主题其他页的回复
  6817. fetchPostOtherPageReplies(href, pageNo) {
  6818. return new Promise((resolve) => {
  6819. $.get(href).then((res) => {
  6820. let s = res.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  6821. let box = $(s[0]).find("#Main .box")[1];
  6822. let cells = box.querySelectorAll(".cell");
  6823. cells = Array.from(cells);
  6824. resolve({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  6825. }).catch((r2) => {
  6826. if (r2.status === 403) {
  6827. functions.cbChecker({ type: "restorePost", value: null });
  6828. }
  6829. });
  6830. });
  6831. },
  6832. //解析页面的回复
  6833. parsePageReplies(nodes) {
  6834. let replyList = [];
  6835. nodes.forEach((node, index) => {
  6836. if (!node.id)
  6837. return;
  6838. let item = {
  6839. level: 0,
  6840. thankCount: 0,
  6841. isThanked: false,
  6842. isOp: false,
  6843. isDup: false,
  6844. id: node.id.replace("r_", "")
  6845. };
  6846. let reply_content = node.querySelector(".reply_content");
  6847. item.reply_content = functions.checkPhotoLink2Img(reply_content.innerHTML);
  6848. item.reply_text = reply_content.textContent;
  6849. let { users, floor } = this.parseReplyContent(item.reply_content);
  6850. item.hideCallUserReplyContent = item.reply_content;
  6851. if (users.length === 1) {
  6852. item.hideCallUserReplyContent = item.reply_content.replace(/@<a href="\/member\/[\s\S]+?<\/a>(\s#[\d]+)?\s(<br>)?/, () => "");
  6853. }
  6854. item.replyUsers = users;
  6855. item.replyFloor = floor;
  6856. let ago = node.querySelector(".ago");
  6857. item.date = ago.textContent;
  6858. let userNode = node.querySelector("strong a");
  6859. item.username = userNode.textContent;
  6860. let avatar = node.querySelector("td img");
  6861. item.avatar = avatar.src;
  6862. let no = node.querySelector(".no");
  6863. item.floor = Number(no.textContent);
  6864. let thank_area = node.querySelector(".thank_area");
  6865. if (thank_area) {
  6866. item.isThanked = thank_area.classList.contains("thanked");
  6867. }
  6868. let small = node.querySelector(".small");
  6869. if (small) {
  6870. item.thankCount = Number(small.textContent);
  6871. }
  6872. let op = node.querySelector(".op");
  6873. if (op) {
  6874. item.isOp = true;
  6875. }
  6876. let mod = node.querySelector(".mod");
  6877. if (mod) {
  6878. item.isMod = true;
  6879. }
  6880. replyList.push(item);
  6881. });
  6882. return replyList;
  6883. },
  6884. //解析回复内容,解析出@用户,回复楼层。用于后续生成嵌套楼层
  6885. parseReplyContent(str) {
  6886. if (!str)
  6887. return;
  6888. let users = [];
  6889. let getUsername = (userStr) => {
  6890. let endIndex = userStr.indexOf('">');
  6891. if (endIndex > -1) {
  6892. let user = userStr.substring(0, endIndex);
  6893. if (!users.find((i) => i === user)) {
  6894. users.push(user);
  6895. }
  6896. }
  6897. };
  6898. let userReg = /@<a href="\/member\/([\s\S]+?)<\/a>/g;
  6899. let has = str.matchAll(userReg);
  6900. let res2 = [...has];
  6901. if (res2.length > 1) {
  6902. res2.map((item) => {
  6903. getUsername(item[1]);
  6904. });
  6905. }
  6906. if (res2.length === 1) {
  6907. getUsername(res2[0][1]);
  6908. }
  6909. let floor = -1;
  6910. if (users.length === 1) {
  6911. let floorReg = /@<a href="\/member\/[\s\S]+?<\/a>[\s]+#([\d]+)/g;
  6912. let hasFloor = str.matchAll(floorReg);
  6913. let res = [...hasFloor];
  6914. if (res.length) {
  6915. floor = Number(res[0][1]);
  6916. }
  6917. }
  6918. return { users, floor };
  6919. },
  6920. //获取主题详情
  6921. async getPostDetail(post, body, htmlText, pageNo = 1) {
  6922. post = await this.parsePostContent(post, body, htmlText);
  6923. return await this.getPostAllReplies(post, body, htmlText, pageNo);
  6924. },
  6925. //解析页面主题列表
  6926. parsePagePostList(list, box) {
  6927. list.forEach((itemDom) => {
  6928. let item_title = itemDom.querySelector(".item_title");
  6929. if (!item_title)
  6930. return;
  6931. let item = getDefaultPost();
  6932. itemDom.classList.add("post-item");
  6933. let a = item_title.querySelector("a");
  6934. let { href, id } = functions.parseA(a);
  6935. item.id = String(Number(id));
  6936. a.href = item.href = href;
  6937. item.url = location.origin + "/api/topics/show.json?id=" + item.id;
  6938. itemDom.classList.add(`id_${id}`);
  6939. itemDom.dataset["href"] = href;
  6940. let td = itemDom.querySelector("td:nth-child(4)");
  6941. if (!td) {
  6942. td = itemDom.querySelector("td:nth-child(2)");
  6943. }
  6944. td.style.position = "relative";
  6945. let toggle = document.createElement("div");
  6946. toggle.dataset["id"] = item.id;
  6947. toggle.classList.add("toggle");
  6948. toggle.innerText = "预览";
  6949. td.append(toggle);
  6950. if (window.config.viewType === "card") {
  6951. window.postList.push(item);
  6952. }
  6953. });
  6954. const setF = (res) => {
  6955. let rIndex = window.postList.findIndex((w) => w.id === res.id);
  6956. if (rIndex > -1) {
  6957. window.postList[rIndex] = Object.assign(window.postList[rIndex], res);
  6958. functions.cbChecker({ type: "syncData" });
  6959. }
  6960. let itemDom = box.querySelector(`.id_${res.id}`);
  6961. itemDom.classList.add("preview");
  6962. if (res.content_rendered) {
  6963. functions.appendPostContent(res, itemDom);
  6964. }
  6965. };
  6966. if (window.config.viewType === "card") {
  6967. let cacheDataStr = localStorage.getItem("cacheData");
  6968. let cacheData = [];
  6969. if (cacheDataStr) {
  6970. cacheData = JSON.parse(cacheDataStr);
  6971. let now = Date.now();
  6972. cacheData = cacheData.filter((v) => {
  6973. return v.created > now / 1e3 - 60 * 60 * 24 * 3;
  6974. });
  6975. }
  6976. let fetchIndex = 0;
  6977. for (let i = 0; i < window.postList.length; i++) {
  6978. let item = window.postList[i];
  6979. let rItem = cacheData.find((w) => w.id === item.id);
  6980. if (rItem) {
  6981. rItem.href = item.href;
  6982. setF(rItem);
  6983. } else {
  6984. fetchIndex++;
  6985. setTimeout(() => {
  6986. $.get(item.url).then((v) => {
  6987. if (v && v.length) {
  6988. let res = getDefaultPost(v[0]);
  6989. res.href = item.href;
  6990. cacheData.push(res);
  6991. localStorage.setItem("cacheData", JSON.stringify(cacheData));
  6992. setF(res);
  6993. }
  6994. });
  6995. }, fetchIndex < 4 ? 0 : (fetchIndex - 4) * 1e3);
  6996. }
  6997. }
  6998. }
  6999. },
  7000. //创建记事本子条目
  7001. async createNoteItem(itemName) {
  7002. return new Promise(async (resolve) => {
  7003. let data = new FormData();
  7004. data.append("content", itemName);
  7005. data.append("parent_id", 0);
  7006. data.append("syntax", 0);
  7007. let apiRes = await fetch(`${location.origin}/notes/new`, { method: "post", body: data });
  7008. console.log(apiRes);
  7009. if (apiRes.redirected && apiRes.status === 200) {
  7010. resolve(apiRes.url.substr(-5));
  7011. return;
  7012. }
  7013. resolve(null);
  7014. });
  7015. },
  7016. //编辑记事本子条目
  7017. async editNoteItem(val, id) {
  7018. let data = new FormData();
  7019. data.append("content", val);
  7020. data.append("syntax", 0);
  7021. let apiRes = await fetch(`${location.origin}/notes/edit/${id}`, {
  7022. method: "post",
  7023. body: data
  7024. });
  7025. return apiRes.redirected && apiRes.status === 200;
  7026. },
  7027. //标签操作
  7028. async saveTags(val) {
  7029. for (const [key, value] of Object.entries(val)) {
  7030. if (!value.length)
  7031. delete val[key];
  7032. }
  7033. return await this.editNoteItem(window.user.tagPrefix + JSON.stringify(val), window.user.tagsId);
  7034. },
  7035. //已读楼层操作
  7036. async saveReadList(val) {
  7037. return;
  7038. },
  7039. //imgur图片删除hash操作
  7040. async saveImgurList(val) {
  7041. return;
  7042. }
  7043. };
  7044. window.vals = {
  7045. isMobile: !document.querySelector("#Rightbar")
  7046. };
  7047. function initMonkeyMenu() {
  7048. try {
  7049. _GM_registerMenuCommand("脚本设置", () => {
  7050. functions.cbChecker({ type: "openSetting" });
  7051. });
  7052. _GM_registerMenuCommand("仓库地址", () => {
  7053. functions.openNewTab(DefaultVal.git, true);
  7054. });
  7055. _GM_registerMenuCommand("反馈 & 建议", functions.feedback);
  7056. } catch (e2) {
  7057. console.error("无法使用Tampermonkey");
  7058. }
  7059. }
  7060. function initStyle() {
  7061. let style2 = `
  7062. html, body {
  7063. font-size: 62.5%;
  7064. }
  7065.  
  7066. :root{
  7067. --box-border-radius:8px;
  7068. }
  7069. .box{
  7070. box-shadow:rgba(0, 0, 0, 0.08) 0px 4px 12px;
  7071. }
  7072. #Tabs{
  7073. border-top-left-radius: var(--box-border-radius) !important;
  7074. border-top-right-radius: var(--box-border-radius) !important;
  7075. }
  7076. #Main .cell .count_livid {
  7077. font-size: 14px;
  7078. font-weight: bold;
  7079. padding: 3px 10px;
  7080. border-radius: 5px;
  7081. }
  7082.  
  7083. #Wrapper {
  7084. height: unset !important;
  7085. width: unset !important;
  7086. }
  7087.  
  7088. #Wrapper > .content {
  7089. height: unset !important;
  7090. width: unset !important;
  7091. max-width:1100px !important;
  7092. }
  7093.  
  7094. .post-item {
  7095. background: white;
  7096. }
  7097.  
  7098. .post-item > .post-content {
  7099. height: 0;
  7100. margin-top: 0;
  7101. }
  7102.  
  7103. .post-item:hover .toggle {
  7104. display: flex;
  7105. }
  7106.  
  7107. .toggle {
  7108. position: absolute;
  7109. right: ${window.config.viewType === "simple" ? "5rem" : 0};
  7110. top: ${window.config.viewType === "simple" ? 0 : "0.5rem"};
  7111. width: 5rem;
  7112. height: 100%;
  7113. display: flex;
  7114. justify-content: flex-end;
  7115. align-items: flex-end;
  7116. cursor: pointer;
  7117. font-size: 1.2rem;
  7118. color: var(--link-color);
  7119. display: none;
  7120. padding-right: 1rem;
  7121. }
  7122.  
  7123. .preview {
  7124. margin: 1rem 0;
  7125. border: 1px solid transparent;
  7126. border-radius: var(--box-border-radius);
  7127. cursor: pointer;
  7128. }
  7129.  
  7130. .preview:hover {
  7131. border: 1px solid #c8c8c8;
  7132. }
  7133.  
  7134. .preview > .post-content {
  7135. height: unset !important;
  7136. margin-top: 0.5rem !important;
  7137. }
  7138.  
  7139. .preview > .post-content.show-all {
  7140. max-height: unset;
  7141. -webkit-mask-image:none;
  7142. }
  7143.  
  7144. .preview .topic-link:link {
  7145. color: black !important;
  7146. }
  7147.  
  7148. .post-content {
  7149. margin-top: 0.5rem;
  7150. display: block;
  7151. max-height: 30rem;
  7152. overflow: hidden;
  7153. text-decoration: unset !important;
  7154. line-break: anywhere;
  7155. -webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);
  7156. }
  7157.  
  7158. .show-more {
  7159. display: none;
  7160. }
  7161.  
  7162. .preview > .show-more {
  7163. font-size: 1.3rem;
  7164. text-align: right;
  7165. height: 3rem;
  7166. display: flex;
  7167. align-items: center;
  7168. justify-content: center;
  7169. position: relative;
  7170. z-index: 9;
  7171. }
  7172.  
  7173. .post-content:visited {
  7174. color: #afb9c1 !important;
  7175. }
  7176.  
  7177. .post-content:link {
  7178. color: #494949;
  7179. }
  7180.  
  7181.  
  7182. .Night .post-item {
  7183. background: #18222d !important;
  7184. }
  7185.  
  7186. .Night .preview {
  7187. border: 1px solid #3b536e;
  7188. }
  7189.  
  7190. .Night .preview > .post-content:link {
  7191. color: #d1d5d9;
  7192. }
  7193.  
  7194. .Night .preview > .post-content:visited {
  7195. color: #393f4e !important;
  7196. }
  7197. .Night .preview .topic-link:link {
  7198. color: #c0dbff !important;
  7199. }
  7200. ${window.config.viewType === "simple" ? `
  7201. ${window.pageType !== PageType.Member ? `
  7202. .item table tr td:first-child{display:none;}
  7203. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  7204. .item table tr td .sep5{display:none;}
  7205. .item table tr td .topic_info{display:none;}
  7206. .item {border-bottom:none;}
  7207. .avatar,#avatar{display:none;}
  7208. ` : ""}
  7209. #Logo {background-image:url('https://i.imgur.com/i9VgUtM.png');}
  7210. .bigger a, .top:nth-last-child(5){color: transparent!important;text-shadow: #b0b0b0 0 0 6px;user-select: none;}
  7211. // .bigger a:before,.top:nth-last-child(5):before{content:'Mona Lisa';position: absolute;background: white;}
  7212. #Rightbar .cell table:first-child tr td:first-child{display:none;}
  7213. ` : ""}
  7214.  
  7215. ${window.config.customBgColor ? `#Wrapper {
  7216. background-color: ${window.config.customBgColor} !important;
  7217. background-image: unset !important;
  7218. }` : ""}
  7219. .top{
  7220. position:relative;
  7221. }
  7222. .new:before{
  7223. content:'new';
  7224. position: absolute;
  7225. background: red;
  7226. font-size: 10px;
  7227. border-radius: 4px;
  7228. padding: 0px 2px;
  7229. color: white;
  7230. right: -9px;
  7231. top: -3px;
  7232. }
  7233. }
  7234. `;
  7235. let addStyle2 = document.createElement("style");
  7236. addStyle2.rel = "stylesheet";
  7237. addStyle2.type = "text/css";
  7238. addStyle2.innerHTML = style2;
  7239. window.document.head.append(addStyle2);
  7240. }
  7241. function qianDao() {
  7242. let timeNow = (/* @__PURE__ */ new Date()).getUTCFullYear() + "/" + ((/* @__PURE__ */ new Date()).getUTCMonth() + 1) + "/" + (/* @__PURE__ */ new Date()).getUTCDate();
  7243. if (window.pageType === PageType.Home) {
  7244. let qiandao = window.query('.box .inner a[href="/mission/daily"]');
  7245. if (qiandao) {
  7246. qianDao_(qiandao, timeNow);
  7247. } else if (window.win().doc.getElementById("gift_v2excellent")) {
  7248. window.win().doc.getElementById("gift_v2excellent").click();
  7249. localStorage.setItem("menu_clockInTime", timeNow);
  7250. console.info("[V2EX - 超级增强] 自动签到完成!");
  7251. } else {
  7252. console.info("[V2EX - 超级增强] 自动签到完成!");
  7253. }
  7254. } else {
  7255. let timeOld = localStorage.getItem("menu_clockInTime");
  7256. if (!timeOld || timeOld != timeNow) {
  7257. qianDaoStatus_(timeNow);
  7258. } else {
  7259. console.info("[V2EX - 超级增强] 自动签到完成!");
  7260. }
  7261. }
  7262. }
  7263. function qianDao_(qiandao, timeNow) {
  7264. let url = window.baseUrl + "/mission/daily/redeem?" + RegExp("once\\=(\\d+)").exec(document.querySelector("div#Top .tools, #menu-body").innerHTML)[0];
  7265. console.log("url", url);
  7266. $.get(url).then((r2) => {
  7267. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7268. let html = $(bodyText[0]);
  7269. if (html.find("li.fa.fa-ok-sign").length) {
  7270. html = html.find("#Main").text().match(/已连续登录 (\d+?) 天/)[0];
  7271. localStorage.setItem("menu_clockInTime", timeNow);
  7272. console.info("[V2EX - 超级增强] 自动签到完成!");
  7273. if (qiandao) {
  7274. qiandao.textContent = `自动签到完成!${html}`;
  7275. qiandao.href = "javascript:void(0);";
  7276. }
  7277. } else {
  7278. _GM_notification({
  7279. text: "自动签到失败!请关闭其他插件或脚本。\n如果连续几天都签到失败,请联系作者解决!",
  7280. timeout: 4e3,
  7281. onclick() {
  7282. functions.feedback();
  7283. }
  7284. });
  7285. console.warn("[V2EX 增强] 自动签到失败!请关闭其他插件或脚本。如果连续几天都签到失败,请联系作者解决!");
  7286. if (qiandao)
  7287. qiandao.textContent = "自动签到失败!请尝试手动签到!";
  7288. }
  7289. });
  7290. }
  7291. function qianDaoStatus_(timeNow) {
  7292. $.get(window.baseUrl + "/mission/daily").then((r2) => {
  7293. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7294. let html = $(bodyText[0]);
  7295. if (html.find('input[value^="领取"]').length) {
  7296. qianDao_(null, timeNow);
  7297. } else {
  7298. console.info("[V2EX 增强] 已经签过到了。");
  7299. localStorage.setItem("menu_clockInTime", timeNow);
  7300. }
  7301. });
  7302. }
  7303. function getNoteItemContent(id, prefix) {
  7304. return new Promise((resolve, reject) => {
  7305. $.get(location.origin + "/notes/edit/" + id).then((r2) => {
  7306. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7307. let body = $(bodyText[0]);
  7308. let text = body.find(".note_editor").text();
  7309. if (text === prefix) {
  7310. resolve({});
  7311. } else {
  7312. let tagJson = text.substring(prefix.length);
  7313. try {
  7314. resolve(JSON.parse(tagJson));
  7315. } catch (e2) {
  7316. console.log("tage", tagJson);
  7317. resolve({});
  7318. }
  7319. }
  7320. });
  7321. });
  7322. }
  7323. function deleteNote(tagsId, cb) {
  7324. fetch(`/notes/${tagsId}`).then((r2) => {
  7325. r2.text().then((a) => {
  7326. let res = a.match(/\?once=([\d]+)/);
  7327. if (res && res[1]) {
  7328. console.log("接口返回了once-str", Number(res[1]));
  7329. fetch(`/notes/delete/${tagsId}?once=${Number(res[1])}`).then((r22) => {
  7330. console.log("r", r22, r22.url === location.origin + "/");
  7331. if (r22.status === 200) {
  7332. if (r22.redirected && r22.url === location.origin + "/") {
  7333. cb();
  7334. }
  7335. } else {
  7336. cb();
  7337. }
  7338. });
  7339. }
  7340. });
  7341. });
  7342. }
  7343. async function initNoteData() {
  7344. $.get(location.origin + "/notes").then(async (r2) => {
  7345. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  7346. let body = $(bodyText[0]);
  7347. let items = body.find("#Main .box .note_item_title a");
  7348. if (window.config.openTag) {
  7349. let tagItems = Array.from(items).filter((v) => v.innerText.includes(window.user.tagPrefix));
  7350. if (tagItems.length) {
  7351. if (tagItems.length > 1) {
  7352. let next = true;
  7353. for (let i = 1; i < tagItems.length - 1; i++) {
  7354. setTimeout(() => {
  7355. if (!next)
  7356. return;
  7357. let tagsId = tagItems[i].href.substr(-5);
  7358. deleteNote(tagsId, () => next = false);
  7359. }, 60 * 1e3 * i);
  7360. }
  7361. }
  7362. window.user.tagsId = tagItems[0].href.substr(-5);
  7363. window.user.tags = await getNoteItemContent(window.user.tagsId, window.user.tagPrefix);
  7364. } else {
  7365. let r22 = await window.parse.createNoteItem(window.user.tagPrefix);
  7366. r22 && (window.user.tagsId = r22);
  7367. }
  7368. }
  7369. functions.cbChecker({ type: "syncData" });
  7370. });
  7371. }
  7372. function addSettingText() {
  7373. let setting = $(`<a href="/" class="top ${window.config.version < DefaultVal.currentVersion ? "new" : ""}">脚本设置</a>`);
  7374. setting.on("click", function(e2) {
  7375. e2.stopPropagation();
  7376. e2.preventDefault();
  7377. this.classList.remove("new");
  7378. functions.cbChecker({ type: "openSetting" });
  7379. });
  7380. $(".tools").prepend(setting);
  7381. }
  7382. async function init() {
  7383. window.addEventListener("error", (e2) => {
  7384. let dom = e2.target;
  7385. let originImgUrl = dom.getAttribute("data-originurl");
  7386. if (originImgUrl) {
  7387. let a = document.createElement("a");
  7388. a.href = originImgUrl;
  7389. a.setAttribute("notice", "此标签由v2ex超级增强脚本转换图片失败后恢复");
  7390. a.innerText = originImgUrl;
  7391. dom.parentNode.replaceChild(a, dom);
  7392. }
  7393. }, true);
  7394. if (window.isNight) {
  7395. document.documentElement.classList.add("dark");
  7396. }
  7397. let { pageData, pageType } = functions.checkPageType();
  7398. window.pageType = pageType;
  7399. window.pageData = pageData;
  7400. initMonkeyMenu();
  7401. let top2 = document.querySelector(".tools .top:nth-child(2)");
  7402. if (top2 && top2.textContent !== "注册") {
  7403. window.user.username = top2.textContent;
  7404. window.user.avatar = $("#Rightbar .box .avatar").attr("src");
  7405. }
  7406. functions.initConfig().then(async (r2) => {
  7407. addSettingText();
  7408. initStyle();
  7409. try {
  7410. if (window.config.autoSignin && window.user.username) {
  7411. qianDao();
  7412. }
  7413. } catch (e2) {
  7414. console.log("签到失败");
  7415. }
  7416. if (window.user.username) {
  7417. initNoteData();
  7418. }
  7419. let box;
  7420. let list;
  7421. let last;
  7422. let headerWrap;
  7423. switch (window.pageType) {
  7424. case PageType.Node:
  7425. box = document.querySelectorAll("#Wrapper #Main .box");
  7426. try {
  7427. headerWrap = $('<div class="post-item"></div>');
  7428. if (window.config.viewType === "card")
  7429. headerWrap[0].classList.add("preview");
  7430. $(box[1]).prepend(headerWrap);
  7431. $(box[1]).children().slice(1, 3).each(function() {
  7432. if (this.classList.contains("cell")) {
  7433. headerWrap.append(this);
  7434. }
  7435. });
  7436. headerWrap = $('<div class="post-item"></div>');
  7437. if (window.config.viewType === "card")
  7438. headerWrap[0].classList.add("preview");
  7439. $(box[1]).append(headerWrap);
  7440. $(box[1]).children().slice(2).each(function() {
  7441. if (this.classList.contains("cell")) {
  7442. headerWrap.append(this);
  7443. }
  7444. });
  7445. box[1].style.boxShadow = "unset";
  7446. box[1].style.background = "unset";
  7447. box[1].style.overflow = "hidden";
  7448. } catch (e2) {
  7449. console.log("PageType-Node解析报错了", e2);
  7450. }
  7451. let topics = box[1].querySelector("#TopicsNode");
  7452. list = topics.querySelectorAll(".cell");
  7453. list[0].before($section);
  7454. window.parse.parsePagePostList(list, box[1]);
  7455. break;
  7456. case PageType.Changes:
  7457. case PageType.Home:
  7458. box = document.querySelector("#Wrapper #Main .box");
  7459. try {
  7460. headerWrap = $('<div class="post-item"></div>');
  7461. if (window.config.viewType === "card")
  7462. headerWrap[0].classList.add("preview");
  7463. $(box).prepend(headerWrap);
  7464. $(box).children().slice(1, 3).each(function() {
  7465. if (!this.classList.contains("item")) {
  7466. headerWrap.append(this);
  7467. }
  7468. });
  7469. last = $(box).children().last();
  7470. last.addClass("cell post-item");
  7471. if (window.config.viewType === "card")
  7472. last[0].classList.add("preview");
  7473. box.style.boxShadow = "unset";
  7474. box.style.background = "unset";
  7475. box.style.overflow = "hidden";
  7476. } catch (e2) {
  7477. console.log("PageType-Home解析报错了", e2);
  7478. }
  7479. list = box.querySelectorAll(".item");
  7480. list[0].before($section);
  7481. window.parse.parsePagePostList(list, box);
  7482. break;
  7483. case PageType.Post:
  7484. box = document.querySelector("#Wrapper #Main .box");
  7485. box.after($section);
  7486. let r22 = await functions.checkPostReplies(window.pageData.id, false);
  7487. if (r22) {
  7488. window.stopMe = true;
  7489. functions.cbChecker({ type: "syncData" });
  7490. functions.cbChecker({ type: "warningNotice", value: "由于回复数量较多,脚本已停止解析楼中楼" });
  7491. return;
  7492. }
  7493. if (window.config.postWidth) {
  7494. let Main = $("#Main");
  7495. Main.css({
  7496. "width": window.config.postWidth,
  7497. margin: "unset"
  7498. });
  7499. $("#Wrapper > .content").css({
  7500. "max-width": "unset",
  7501. display: "flex",
  7502. "justify-content": "center",
  7503. gap: "20px"
  7504. });
  7505. Main.after($("#Rightbar"));
  7506. }
  7507. let post = getDefaultPost({ id: window.pageData.id });
  7508. let body = $(document.body);
  7509. let htmlText = document.documentElement.outerHTML;
  7510. window.parse.parsePostContent(
  7511. post,
  7512. body,
  7513. htmlText
  7514. ).then(async (res) => {
  7515. await functions.cbChecker({ type: "postContent", value: res });
  7516. await window.parse.parseOp(res);
  7517. });
  7518. window.parse.getPostAllReplies(
  7519. post,
  7520. body,
  7521. htmlText,
  7522. window.pageData.pageNo
  7523. ).then(async (res1) => {
  7524. await functions.cbChecker({ type: "postReplies", value: res1 });
  7525. });
  7526. break;
  7527. case PageType.Member:
  7528. box = document.querySelectorAll("#Wrapper #Main .box");
  7529. window.targetUserName = box[0].querySelector("h1").textContent;
  7530. if (window.config.openTag) {
  7531. box[0].style.borderBottom = "none";
  7532. box[0].style["border-bottom-left-radius"] = "0";
  7533. box[0].style["border-bottom-right-radius"] = "0";
  7534. }
  7535. try {
  7536. headerWrap = $('<div class="post-item"></div>');
  7537. if (window.config.viewType === "card")
  7538. headerWrap[0].classList.add("preview");
  7539. $(box[1]).prepend(headerWrap);
  7540. $(box[1]).children().slice(1, 2).each(function() {
  7541. if (!this.classList.contains("item")) {
  7542. headerWrap.append(this);
  7543. }
  7544. });
  7545. last = $(box[1]).children().last();
  7546. last.addClass("cell post-item");
  7547. if (window.config.viewType === "card")
  7548. last[0].classList.add("preview");
  7549. box[1].style.boxShadow = "unset";
  7550. box[1].style.background = "unset";
  7551. box[1].style.overflow = "hidden";
  7552. } catch (e2) {
  7553. console.log("PageType-Member解析报错了", e2);
  7554. }
  7555. list = box[1].querySelectorAll(".cell");
  7556. box[0].after($section);
  7557. window.parse.parsePagePostList(list, box[1]);
  7558. break;
  7559. default:
  7560. window.stopMe = true;
  7561. functions.cbChecker({ type: "syncData" });
  7562. console.error("未知页面");
  7563. break;
  7564. }
  7565. });
  7566. }
  7567. window.canParseV2exPage = !window.location.search.includes("script");
  7568. if (window.canParseV2exPage) {
  7569. init();
  7570. } else {
  7571. let box = document.querySelector("#Wrapper #Main .box");
  7572. box.after($section);
  7573. window.stopMe = true;
  7574. functions.cbChecker({ type: "syncData" });
  7575. if (window.location.search.includes("script=0")) {
  7576. functions.cbChecker({ type: "warningNotice", value: "脚本无法查看此主题,已为您单独打开此主题" });
  7577. }
  7578. if (window.location.search.includes("script=1")) {
  7579. functions.cbChecker({ type: "warningNotice", value: "由于回复数量较多,已为您单独打开此主题并停止解析楼中楼" });
  7580. }
  7581. }
  7582. }
  7583. if (!isMobile) {
  7584. (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:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-e7c0fbef]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-e7c0fbef]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-e7c0fbef],body[data-v-e7c0fbef]{font-size:62.5%}[data-v-e7c0fbef]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-e7c0fbef]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-e7c0fbef]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-e7c0fbef]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-e7c0fbef]{justify-content:flex-end}.flex-center[data-v-e7c0fbef]{justify-content:center}.p1[data-v-e7c0fbef]{padding:1rem}.p2[data-v-e7c0fbef]{padding:2rem}.p0[data-v-e7c0fbef]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-e7c0fbef]{text-underline-offset:.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:.6rem}.tool>svg[data-v-e7c0fbef]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-e7c0fbef]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-e7c0fbef]{cursor:default}.tool.no-hover[data-v-e7c0fbef]:hover{background:unset!important}.tool.disabled[data-v-e7c0fbef]{cursor:not-allowed}.tool.disabled[data-v-e7c0fbef]:hover{background:unset!important}.my-node[data-v-e7c0fbef]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-e7c0fbef]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-e7c0fbef]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-e7c0fbef]{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;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}.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)}.pop-confirm-content[data-v-7d29b3cc]{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:1001}.pop-confirm-content .text[data-v-7d29b3cc]{text-align:start;font-size:1.6rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-7d29b3cc]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}.setting-modal .modal-root[data-v-cb13d533]{z-index:9;background:var(--color-main-bg);border-radius:1.6rem;font-size:1.4rem;overflow:hidden;color:var(--color-font-pure)}.setting-modal .modal-root .modal-header[data-v-cb13d533]{padding:1.4rem;display:flex;justify-content:center;position:relative}.setting-modal .modal-root .modal-header .title[data-v-cb13d533]{font-size:2.2rem;text-align:left;margin-bottom:0}.setting-modal .modal-root .modal-header svg[data-v-cb13d533]{position:absolute;right:1rem;cursor:pointer;font-size:2.6rem}.setting-modal .modal-root .body[data-v-cb13d533]{width:60rem}.setting-modal .modal-root .body .modal-content[data-v-cb13d533]{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-cb13d533]{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-df0e0e8f]{z-index:9;background:var(--color-main-bg);border-radius:1.6rem;font-size:1.4rem;overflow:hidden;color:var(--color-font-pure)}.setting-modal .modal-root .modal-header[data-v-df0e0e8f]{padding:2.4rem;display:flex;justify-content:space-between}.setting-modal .modal-root .modal-header .title[data-v-df0e0e8f]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.setting-modal .modal-root .modal-header svg[data-v-df0e0e8f]{cursor:pointer;font-size:2.6rem}.setting-modal .modal-root .body[data-v-df0e0e8f]{width:45vw;height:70vh;display:flex}.setting-modal .modal-root .body .left[data-v-df0e0e8f]{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-df0e0e8f]{padding:1rem 2rem;display:flex;flex-direction:column;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab[data-v-df0e0e8f]{cursor:pointer;padding:1rem 1.5rem;border-radius:.8rem;display:flex;align-items:center;gap:1rem}.setting-modal .modal-root .body .left .tabs .tab.active[data-v-df0e0e8f]{background:var(--color-item-bg)}.setting-modal .modal-root .body .left .icons[data-v-df0e0e8f]{display:flex;gap:1rem;margin-bottom:2rem;font-size:2.4rem}.setting-modal .modal-root .body .modal-content[data-v-df0e0e8f]{background:var(--color-second-bg);flex:1;height:100%;box-sizing:border-box;padding:1rem 1rem 1rem 2rem;border-radius:1.6rem;display:flex}.setting-modal .modal-root .body .modal-content .scroll[data-v-df0e0e8f]{flex:1;padding-right:1rem;overflow:auto}.setting-modal .modal-root .body .modal-content .scroll .row[data-v-df0e0e8f]{min-height:5rem;display:flex;justify-content:space-between;align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper[data-v-df0e0e8f]{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-df0e0e8f]{text-align:right;font-size:1.4rem;color:gray}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key[data-v-df0e0e8f]{align-items:center}.setting-modal .modal-root .body .modal-content .scroll .row .wrapper .set-key input[data-v-df0e0e8f]{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-df0e0e8f]{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-df0e0e8f]{font-size:1.8rem}.setting-modal .modal-root .body .modal-content .scroll .desc[data-v-df0e0e8f]{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-df0e0e8f]{text-align:start;font-size:1.6rem;padding-bottom:10rem}.setting-modal .modal-root .body .modal-content .scroll .line[data-v-df0e0e8f]{border-bottom:1px solid #c4c3c3}.Author[data-v-53261a54]{display:flex;align-items:center;justify-content:space-between;font-size:1.2rem;position:relative}.Author.expand[data-v-53261a54]{margin-bottom:0}.Author .Author-left[data-v-53261a54]{display:flex;align-items:center;max-width:65%;word-break:break-all}.Author .Author-left .username[data-v-53261a54]{font-size:1.4rem;margin-right:1rem}.Author .Author-left .expand-icon[data-v-53261a54]{cursor:pointer;margin-right:.8rem;width:2rem;height:2rem;transform:rotate(90deg)}.Author .Author-left .avatar[data-v-53261a54]{margin-right:1rem;display:flex}.Author .Author-left .avatar img[data-v-53261a54]{width:2.8rem;height:2.8rem;border-radius:.4rem}.Author .Author-left .texts[data-v-53261a54]{flex:1}.Author .Author-left .owner[data-v-53261a54]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.Author .Author-left .dup[data-v-53261a54]{display:inline-block;background-color:transparent;color:red;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid red;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.Author .Author-left .mod[data-v-53261a54]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.Author:hover .add-tag[data-v-53261a54]{display:inline-block}.Author .Author-right[data-v-53261a54]{position:absolute;right:0;display:flex;align-items:center}.Author .Author-right .toolbar[data-v-53261a54]{display:flex;align-items:center;color:var(--color-gray);opacity:0;gap:.5rem}.Author .Author-right .toolbar[data-v-53261a54]:hover{opacity:1}.post-editor-wrapper[data-v-4522f98e]{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-4522f98e]{border:1px solid var(--color-line)}.post-editor-wrapper.reply-post.isFocus .post-editor[data-v-4522f98e]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment[data-v-4522f98e]{border-radius:var(--box-border-radius);overflow:hidden;border:1px solid var(--color-line)}.post-editor-wrapper.reply-comment.isFocus[data-v-4522f98e]{border:1px solid var(--color-active)}.post-editor-wrapper.reply-comment .toolbar[data-v-4522f98e]{background:var(--color-editor-toolbar)}.post-editor-wrapper .post-editor[data-v-4522f98e]{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-4522f98e]{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-4522f98e]{display:flex;align-items:center;gap:1rem;font-size:2.6rem}.post-editor-wrapper .toolbar .left svg[data-v-4522f98e]{cursor:pointer}.post-editor-wrapper .toolbar .left .upload[data-v-4522f98e]{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-4522f98e]{width:2.6rem;height:2.6rem;cursor:pointer;position:absolute;opacity:0}.post-editor-wrapper .toolbar span[data-v-4522f98e]{color:gray;font-size:1.3rem}.post-editor-wrapper .get-cursor[data-v-4522f98e]{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-4522f98e]{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-4522f98e]{cursor:pointer;position:absolute;right:.8rem;font-size:2.4rem}.post-editor-wrapper .emoticon-pack .list[data-v-4522f98e]{margin:1rem 0}.post-editor-wrapper .emoticon-pack img[data-v-4522f98e]{cursor:pointer;width:3rem;height:3rem;padding:.5rem}.post-editor-wrapper .emoticon-pack span[data-v-4522f98e]{display:inline-block;cursor:pointer;font-size:2.3rem;padding:.5rem}.v-enter-active[data-v-2c9a538c],.v-leave-active[data-v-2c9a538c]{transition:opacity .3s ease}.v-enter-from[data-v-2c9a538c],.v-leave-to[data-v-2c9a538c]{opacity:0}.username[data-v-2c9a538c]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-2c9a538c]{font-size:1.2rem;font-weight:700;color:#e02a2a}.owner[data-v-2c9a538c]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;margin-right:1rem;transform:scale(.8)}.mod[data-v-2c9a538c]{display:inline-block;background-color:transparent;color:#1484cd;border-radius:.3rem;padding:0 .3rem;cursor:default;border:2px solid #1484cd;font-size:1.2rem;font-weight:700;transform:scale(.8);background:#1484cd;color:#fff;margin-right:1rem}.my-tag[data-v-2c9a538c]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-2c9a538c]{display:inline}.my-tag .remove[data-v-2c9a538c]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-2c9a538c]{font-size:2.4rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;position:absolute;display:none}.floor[data-v-2c9a538c]{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-2c9a538c]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-2c9a538c]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-2c9a538c],body[data-v-2c9a538c]{font-size:62.5%}[data-v-2c9a538c]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-2c9a538c]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-2c9a538c]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-2c9a538c]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-2c9a538c]{justify-content:flex-end}.flex-center[data-v-2c9a538c]{justify-content:center}.p1[data-v-2c9a538c]{padding:1rem}.p2[data-v-2c9a538c]{padding:2rem}.p0[data-v-2c9a538c]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-2c9a538c]{text-underline-offset:.7ex;text-decoration:underline 1px}a[data-v-2c9a538c]{text-decoration:none;cursor:pointer}a[data-v-2c9a538c]:hover{text-decoration:underline}.tool[data-v-2c9a538c]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg[data-v-2c9a538c]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-2c9a538c]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-2c9a538c]{cursor:default}.tool.no-hover[data-v-2c9a538c]:hover{background:unset!important}.tool.disabled[data-v-2c9a538c]{cursor:not-allowed}.tool.disabled[data-v-2c9a538c]:hover{background:unset!important}.my-node[data-v-2c9a538c]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-2c9a538c]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-2c9a538c]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-2c9a538c]{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;box-sizing:border-box;transition:background-color .3s}.my-cell[data-v-2c9a538c]{color:var(--color-font);padding:.8rem 1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid var(--color-line)}.modal[data-v-2c9a538c]{position:fixed;z-index:1001;width:100vw;height:100vh;left:0;top:0;display:flex;justify-content:center;align-items:center}.modal .title[data-v-2c9a538c]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-2c9a538c]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-2c9a538c]{position:relative}.modal .mask[data-v-2c9a538c]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-2c9a538c]{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid var(--color-radio-border);background:var(--box-background-alt-color)}.radio-group2 .radio[data-v-2c9a538c]{cursor:pointer;background:transparent;padding:.5rem 1.2rem;border-left:1px solid var(--color-radio-border);font-size:1.3rem;color:var(--color-gray)}.radio-group2 .radio[data-v-2c9a538c]:first-child{border-left:none}.radio-group2 .active[data-v-2c9a538c]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-2c9a538c]{position:relative;display:inline-flex;justify-content:center}input[data-v-2c9a538c]{height:3rem;outline:unset;border:1px solid var(--color-input-border);padding:0 .5rem;border-radius:5px;box-sizing:border-box;transition:all .3s;background:var(--color-input-bg);color:var(--color-font)}input[data-v-2c9a538c]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-2c9a538c]:focus{border:1px solid var(--color-active)}.danger[data-v-2c9a538c]{color:red!important}.html-wrapper[data-v-2c9a538c]{position:relative}.html-wrapper .mask[data-v-2c9a538c]{max-height:90rem;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 80%,transparent)}.html-wrapper .expand[data-v-2c9a538c]{position:absolute;z-index:1;bottom:2rem;padding:.2rem 1.5rem;border-radius:2rem;border:1px solid gray;background:white;color:gray;left:50%;transform:translate(-50%);cursor:pointer}.comment[data-v-67807ede]{width:100%;box-sizing:border-box;margin-top:.6rem}.comment.isLevelOne[data-v-67807ede]{border-bottom:1px solid var(--color-line);padding:.8rem 1rem;margin-top:0}.comment.ding[data-v-67807ede]{background:rgba(255,255,0,.3)!important}.comment.isSimple .avatar[data-v-67807ede],.comment.isSimple .expand-line[data-v-67807ede]{display:none}.comment.isSimple .simple-wrapper[data-v-67807ede]{padding-left:2.8rem}.comment.isSimple .w[data-v-67807ede]{padding-left:0!important;padding-top:.5rem}.comment .comment-content-w .more[data-v-67807ede]{text-align:center;margin:2rem 0}.comment .comment-content[data-v-67807ede]{display:flex;position:relative}.comment .comment-content .expand-line[data-v-67807ede]{cursor:pointer;margin-top:.6rem;width:2.8rem;min-width:2.8rem;position:relative}.comment .comment-content .expand-line[data-v-67807ede]:after{position:absolute;left:50%;content:" ";height:100%;width:0;border-right:1px solid var(--color-line)}.comment .comment-content .expand-line[data-v-67807ede]:hover:after{border-right:2px solid var(--color-active)}.comment .comment-content .right[data-v-67807ede]{flex:1;width:calc(100% - 3rem)}.comment .comment-content .right .w[data-v-67807ede]{padding-left:1rem}.comment .comment-content .right .w .post-editor-wrapper[data-v-67807ede]{margin-top:1rem}.wrong-wrapper[data-v-67807ede]{font-size:1.4rem;margin-bottom:1rem}.wrong-wrapper span[data-v-67807ede]{cursor:pointer}.wrong-wrapper .del-line[data-v-67807ede]{text-decoration:line-through}.wrong-wrapper .wrong-icon[data-v-67807ede]{margin-left:.5rem}.wrong-wrapper .warning[data-v-67807ede]{border-top:1px solid #e1e1e1;border-bottom:1px solid #e1e1e1;padding:1rem 0;margin-top:1rem;font-size:1.2rem;color:red}.toolbar[data-v-e3df61b2]{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-87050bc7]{width:100%;box-sizing:border-box;display:flex;gap:1rem;padding:1rem;border-bottom:1px solid var(--color-line)}.comment.isSimple .avatar[data-v-87050bc7]{display:none}.comment.isSimple .reply_content[data-v-87050bc7]{margin-top:.5rem!important}.comment .avatar[data-v-87050bc7]{display:flex}.comment .avatar img[data-v-87050bc7]{width:3.8rem;height:3.8rem;border-radius:.3rem}.comment .comment-body[data-v-87050bc7]{flex:1;display:flex;flex-direction:column}.comment .comment-body .texts[data-v-87050bc7]{display:flex;align-items:center}.comment .comment-body .reply_content[data-v-87050bc7]{margin-top:1rem;max-width:calc(100% - 5rem)}.comment .isRight[data-v-87050bc7]{align-items:flex-end}.comment .isRight .owner[data-v-87050bc7],.comment .isRight .mod[data-v-87050bc7],.comment .isRight .username[data-v-87050bc7]{margin:0 0 0 1rem}.comment .Author-right[data-v-87050bc7]{display:flex;flex-direction:column;align-items:center}.comment .Author-right .floor[data-v-87050bc7]{margin-left:0}.comment .Author-right .jump[data-v-87050bc7]{color:#929596;margin-top:.4rem;font-size:1.4rem}.comment .point[data-v-87050bc7]{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}.v-enter-active[data-v-165fdc78],.v-leave-active[data-v-165fdc78]{transition:opacity .3s ease}.v-enter-from[data-v-165fdc78],.v-leave-to[data-v-165fdc78]{opacity:0}.username[data-v-165fdc78]{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num[data-v-165fdc78]{font-size:1.2rem;font-weight:700;color:#e02a2a}.owner[data-v-165fdc78]{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-165fdc78]{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-165fdc78]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-165fdc78]{display:inline}.my-tag .remove[data-v-165fdc78]{cursor:pointer;margin-left:.5rem;display:none}.add-tag[data-v-165fdc78]{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-165fdc78]{margin-left:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}[data-v-165fdc78]:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark[data-v-165fdc78]{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html[data-v-165fdc78],body[data-v-165fdc78]{font-size:62.5%}[data-v-165fdc78]::-webkit-scrollbar{width:1rem;height:1rem}[data-v-165fdc78]::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}[data-v-165fdc78]::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex[data-v-165fdc78]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-165fdc78]{justify-content:flex-end}.flex-center[data-v-165fdc78]{justify-content:center}.p1[data-v-165fdc78]{padding:1rem}.p2[data-v-165fdc78]{padding:2rem}.p0[data-v-165fdc78]{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http][data-v-165fdc78]{text-underline-offset:.7ex;text-decoration:underline 1px}a[data-v-165fdc78]{text-decoration:none;cursor:pointer}a[data-v-165fdc78]:hover{text-decoration:underline}.tool[data-v-165fdc78]{position:relative;display:flex;align-items:center;border-radius:.3rem;cursor:pointer;height:2.6rem;padding:0 .5rem;gap:.6rem}.tool>svg[data-v-165fdc78]{width:1.6rem!important;height:1.6rem!important}.tool[data-v-165fdc78]:hover{background:var(--color-third-bg)}.tool.no-hover[data-v-165fdc78]{cursor:default}.tool.no-hover[data-v-165fdc78]:hover{background:unset!important}.tool.disabled[data-v-165fdc78]{cursor:not-allowed}.tool.disabled[data-v-165fdc78]:hover{background:unset!important}.my-node[data-v-165fdc78]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-165fdc78]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-165fdc78]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box[data-v-165fdc78]{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-165fdc78]{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-165fdc78]{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-165fdc78]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-165fdc78]{display:flex;align-items:center;padding:.6rem 0}.modal .option>span[data-v-165fdc78]{position:relative}.modal .mask[data-v-165fdc78]{position:fixed;width:100vw;height:100vh;left:0;top:0;background-color:#1d1c1c47}.radio-group2[data-v-165fdc78]{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-165fdc78]{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-165fdc78]:first-child{border-left:none}.radio-group2 .active[data-v-165fdc78]{background:var(--color-third-bg);color:var(--color-font)}.pop-confirm[data-v-165fdc78]{position:relative;display:inline-flex;justify-content:center}input[data-v-165fdc78]{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-165fdc78]:hover{border:1px solid var(--color-input-border-hover)}input[data-v-165fdc78]:focus{border:1px solid var(--color-active)}.danger[data-v-165fdc78]{color:red!important}.Post[data-v-165fdc78]{position:unset!important;background:transparent!important;overflow:unset!important}.Post .main[data-v-165fdc78]{background:transparent!important;padding:unset!important;width:100%!important}.Post .close-btn[data-v-165fdc78]{display:none}.post-detail[data-v-165fdc78]{text-align:start;position:fixed;z-index:1000;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-165fdc78] .subtle{background-color:#ecfdf5e6;border-left:4px solid #a7f3d0}.post-detail.isNight[data-v-165fdc78] .subtle{background-color:#1a3332;border-left:4px solid #047857}.post-detail .main[data-v-165fdc78]{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-165fdc78]{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-165fdc78]{display:inline-block}.post-detail .main .main-wrapper .loading-wrapper[data-v-165fdc78]{height:20rem;display:flex;justify-content:center;align-items:center}.post-detail .main .main-wrapper #no-comments-yet[data-v-165fdc78]{color:#a9a9a9;font-weight:700;text-align:center;width:100%;margin-bottom:2rem;box-sizing:border-box}.post-detail .main .relationReply[data-v-165fdc78]{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-165fdc78]{background:var(--color-second-bg);border-radius:var(--box-border-radius) var(--box-border-radius) 0 0}.post-detail .main .relationReply .comments[data-v-165fdc78]{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-165fdc78]{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-165fdc78]{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-165fdc78],.post-detail .main .call-list .call-item[data-v-165fdc78]:hover,.post-detail .main .call-list .call-item.select[data-v-165fdc78]{background:var(--color-main-bg);text-decoration:none}.post-detail .main .call-list .call-item[data-v-165fdc78]:nth-child(1){border-top:1px solid transparent}@media screen and (max-width: 1500px){.post-detail .main-wrapper[data-v-165fdc78]{width:65vw!important}}@media screen and (max-width: 1280px){.post-detail .main-wrapper[data-v-165fdc78]{width:75vw!important}}@media screen and (max-width: 960px){.post-detail .main-wrapper[data-v-165fdc78]{width:100vw!important}}.post-detail .scroll-top[data-v-165fdc78]{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 .scroll-top svg[data-v-165fdc78]{font-size:2.4rem}.post-detail .refresh[data-v-165fdc78]{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-165fdc78]{font-size:2.4rem}.post-detail .scroll-to[data-v-165fdc78]{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-165fdc78]{font-size:2.4rem}.post-detail .scroll-to input[data-v-165fdc78]{height:2.6rem;width:3.6rem;font-size:1.4rem;text-align:center;color:gray}.post-detail .close-btn[data-v-165fdc78]{color:var(--color-font-3);cursor:pointer;position:fixed;top:3rem;transform:translate(4rem);font-size:1.6rem}.post-detail .top-reply[data-v-165fdc78]{color:var(--color-font-3);cursor:pointer;font-size:2rem;display:flex}.base64_tooltip[data-v-c50fb66c]{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-c50fb66c]{margin-left:1rem;font-size:3rem;color:var(--color-gray)}.base64_tooltip[data-v-c50fb66c] .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 .wrapper[data-v-341122ff]{z-index:9;background:var(--color-main-bg);color:var(--color-font-8);border-radius:1.6rem;font-size:1.4rem;padding:2rem 4rem;width:25rem}.tag-modal .wrapper .title[data-v-341122ff]{font-weight:700}.tag-modal .wrapper .btns[data-v-341122ff]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1.5rem;font-size:1.4rem}.msgs[data-v-b73f4332]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.tag-modal .modal-root[data-v-882b932b]{z-index:9;background:var(--color-second-bg);color:var(--color-font-8);border-radius:1.6rem;font-size:1.4rem;width:50vw;height:70vh;display:flex;flex-direction:column}.tag-modal .modal-root .modal-header[data-v-882b932b]{padding:2.4rem;display:flex;justify-content:space-between}.tag-modal .modal-root .modal-header .title[data-v-882b932b]{font-size:2.6rem;font-weight:700;text-align:left;margin-bottom:0}.tag-modal .modal-root .modal-header i[data-v-882b932b]{cursor:pointer;font-size:2.2rem}.tag-modal .modal-root .modal-body[data-v-882b932b]{padding:2rem;padding-top:0;flex:1;overflow:auto}.tag-modal .modal-root .modal-body[data-v-882b932b] .cell{padding:2rem}.v-enter-active,.v-leave-active{transition:opacity .3s ease}.v-enter-from,.v-leave-to{opacity:0}.username{font-weight:700;font-size:1.4rem;margin-right:1rem}.link-num{font-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:1rem;font-size:1.1rem;line-height:1rem;border-radius:.5rem;display:inline-block;background-color:var(--color-floor);color:var(--color-floor-font);padding:3px 9px;cursor:default}:root{--color-main-bg: #e2e2e2;--color-second-bg: white;--color-third-bg: #e2e2e2;--color-item-bg: white;--color-swtich-bg: #dcdfe6;--color-active: #409eff;--color-font: #999;--color-font-8: rgba(0, 0, 0, .8);--color-font-3: rgba(0, 0, 0, .3);--color-font-pure: black;--color-input-bg: white;--color-input-border: #e2e2e2;--color-input-border-hover: #a3a6ad;--color-radio-border: #e2e2e2;--color-tooltip-bg: white;--color-tooltip-shadow: #bbbbbb;--color-scrollbar: #93ade3;--color-line: #e2e2e2;--color-loading-1: #00000033;--color-loading-2: #000;--color-floor: #f0f0f0;--color-floor-font: #bdbdbd;--color-editor-toolbar: #f6f7f8;--color-sp-btn-bg: #f1f1f1;--color-call-list-bg: white}html.dark{--color-main-bg: #22303f;--color-second-bg: #18222d;--color-third-bg: #31475e;--color-item-bg: #18222d;--color-swtich-bg: #4c4d4f;--color-active: #409eff;--color-font: rgba(255, 255, 255, .5);--color-font-8: rgba(255, 255, 255, .8);--color-font-3: rgba(255, 255, 255, .3);--color-font-pure: white;--color-input-bg: #333333;--color-input-border: #6c6e72;--color-input-border-hover: #a3a6ad;--color-radio-border: #454847;--color-tooltip-bg: #31475e;--color-tooltip-shadow: #3b3b3b;--color-scrollbar: #5c5d5e;--color-line: var(--box-border-color);--color-loading-1: rgba(178, 177, 177, .2);--color-loading-2: #ffffff;--color-floor: #293b4d;--color-floor-font: rgba(255, 255, 255, .3);--color-editor-toolbar: var(--box-background-hover-color);--color-sp-btn-bg: #31475e;--color-call-list-bg: #31475e}html,body{font-size:62.5%}::-webkit-scrollbar{width:1rem;height:1rem}::-webkit-scrollbar-track{background:transparent;border-radius:.2rem}::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:1rem}.flex{display:flex;align-items:center;justify-content:space-between}.flex-end{justify-content:flex-end}.flex-center{justify-content:center}.p1{padding:1rem}.p2{padding:2rem}.p0{padding:0!important}body :is(.topic_content,.reply_content) a[href^=http]{text-underline-offset:.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:.6rem}.tool>svg{width:1.6rem!important;height:1.6rem!important}.tool:hover{background:var(--color-third-bg)}.tool.no-hover{cursor:default}.tool.no-hover:hover{background:unset!important}.tool.disabled{cursor:not-allowed}.tool.disabled:hover{background:unset!important}.my-node{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node:hover{text-decoration:none;background:#e2e2e2}.msgs{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.my-box{box-shadow:0 2px 3px #0000001a;box-shadow:#00000014 0 4px 12px;border-radius:var(--box-border-radius);background:var(--box-background-color);margin-bottom:2rem;width:100%;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}.target-user-tags[data-v-38726989]{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-38726989]{display:inline-block}.loaded[data-v-38726989]{font-size:1.4rem;display:flex;align-items:center;gap:1rem;color:var(--color-font-pure)} ');
  7585. console.log("V2EX PC端");
  7586. run();
  7587. let vueApp = vue.createApp(App);
  7588. vueApp.config.unwrapInjectedRef = true;
  7589. vueApp.mount($section);
  7590. }
  7591.  
  7592. })(Vue);