V2Next

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

目前為 2024-01-31 提交的版本,檢視 最新版本

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