V2EX - 超级增强

楼中楼回复(支持感谢数排序)、自动签到、快捷回复图片和表情、列表预览内容、点击帖子弹框展示详情、对用户打标签、回复上下文、记录上次阅读位置、自定义背景、使用 SOV2EX 搜索、正文超长自动折叠、划词 base64 解码、一键@所有人,@管理员、操作按钮(感谢、收藏、回复、隐藏)异步请求、支持黑暗模式

当前为 2023-07-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name V2EX - 超级增强
  3. // @namespace http://tampermonkey.net/
  4. // @version 5.7
  5. // @author zyronon
  6. // @description 楼中楼回复(支持感谢数排序)、自动签到、快捷回复图片和表情、列表预览内容、点击帖子弹框展示详情、对用户打标签、回复上下文、记录上次阅读位置、自定义背景、使用 SOV2EX 搜索、正文超长自动折叠、划词 base64 解码、一键@所有人,@管理员、操作按钮(感谢、收藏、回复、隐藏)异步请求、支持黑暗模式
  7. // @license GPL License
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=v2ex.com
  9. // @match https://*.v2ex.com/
  10. // @match https://*.v2ex.com/?tab=*
  11. // @match https://*.v2ex.com/t/*
  12. // @match https://*.v2ex.com/recent*
  13. // @match https://*.v2ex.com/go/*
  14. // @require https://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.prod.js
  15. // @grant GM_notification
  16. // @grant GM_openInTab
  17. // @grant GM_registerMenuCommand
  18. // ==/UserScript==
  19.  
  20. (t=>{const e=document.createElement("style");e.dataset.source="vite-plugin-monkey",e.textContent=t,document.head.append(e)})(' .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}.op{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}.floor{margin-left:1rem;font-size:1.2rem;line-height:1rem;border-radius:1rem;display:inline-block;background-color:#f0f0f0;color:#ccc;padding:.2rem .5rem;cursor:default}html,body{font-size:62.5%}.flex{display:flex;align-items:center;justify-content:space-between}.flex-end{justify-content:flex-end}.flex-center{justify-content:center}.p1{padding:1rem}.p0{padding:0!important}.post-author{display:flex;align-items:center;position:relative;color:#ccc!important}.post-author>.username{font-size:1.2rem}.sticky{position:sticky;bottom:0}.sticky[stuck]{box-shadow:0 2px 20px #00000059}a{color:#778087;text-decoration:none;cursor:pointer}a:hover{text-decoration:underline}.base-loading{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle infinite 1s linear}.loading-c{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle infinite 1s linear;width:3rem;height:3rem}.loading-b{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle infinite 1s linear;border-color:#ffffff rgba(178,177,177,.2) rgba(178,177,177,.2) rgba(178,177,177,.2);width:3rem;height:3rem}@keyframes circle{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.button{cursor:pointer;padding:.4rem 2.4rem;border-radius:5px;display:inline-flex;justify-content:center;align-items:center;font-weight:700;font-size:1.2rem;color:#fff;background:#40a9ff;border:1px solid #40a9ff;user-select:none}.button:hover{opacity:.9}.button.info{color:#000;border:1px solid #40a9ff;background:white}.button.gray{color:#f5f5f5;border:1px solid #b6b6b6;background:#b6b6b6}.button.light{color:gray;border:1px solid #e2e2e2;background:#e2e2e2}.button:before{content:" ";border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle infinite 1s linear;border-color:#fff transparent transparent transparent;width:1rem;height:1rem;margin-right:1rem;display:none}.button.loading{cursor:not-allowed;opacity:.5}.button.loading:before{display:block}.button.disabled{cursor:not-allowed;color:#c6c6c6;background:#8d8d8d;border:1px solid transparent}.button.isNight{color:#c6c6c6;background:#2b4054;border:1px solid transparent}.tool{position:relative;margin-left:1rem;display:flex;align-items:center;font-size:1.2rem;font-weight:700;border-radius:.2rem;cursor:pointer;height:3rem;padding:0 .5rem}.tool:before{content:" ";border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle infinite 1s linear;border-color:transparent #929596 #929596 #929596;width:1rem;height:1rem;margin-left:1rem;display:none}.tool.loading{cursor:not-allowed;opacity:.5}.tool.loading:before{display:block}.tool.loading:hover{background:unset}.tool>svg{width:1.6rem!important;height:1.6rem!important;margin-right:.4rem;box-sizing:border-box;border-radius:.2rem}.tool:hover{background:#e8e8e8}.tool.no-hover{cursor:default}.tool.no-hover:hover{background:unset}.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}.msg{cursor:default;margin-bottom:2rem;background:white;display:flex;color:#000;font-size:1.4rem;box-sizing:border-box;border-radius:.4rem;box-shadow:0 0 1rem 1px silver}.msg.success .left{background:#40a9ff}.msg.warning .left{background:#c8c002}.msg.error .left{background:red}.msg .left{border-radius:.4rem 0 0 .4rem;display:flex;align-items:center;background:#40a9ff}.msg .left svg{margin:0 .3rem;cursor:pointer}.msg .right{flex:1;padding:1rem 2rem;display:flex;justify-content:space-between;align-items:center}.line{border-bottom:1px solid #e2e2e2}.my-box{box-shadow:0 2px 3px #0000001a;border-radius:.4rem;background:white;margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box}.my-cell{padding:1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid #e2e2e2}.f14{font-size:1.4rem}.switch{width:4.5rem;height:2rem;border-radius:2rem;position:relative;display:flex;align-items:center;transition:all .3s}.switch.light{border:1px solid #e2e2e2}.switch.light.active{background:#e2e2e2}.switch.light.active:before{right:.2rem;background:white}.switch.light:before{background:#e2e2e2}.switch.gray{border:1px solid #ccc}.switch.gray.active{background:#ccc}.switch.gray.active:before{right:.2rem;background:white}.switch.gray:before{background:#ccc}.switch.isNight{border:1px solid #31475e}.switch.isNight.active{background:#31475e}.switch.isNight.active:before{right:.2rem;background:gray}.switch.isNight:before{background:#31475e}.switch:before{position:absolute;content:" ";transition:all .3s;right:calc(100% - 2rem);width:1.8rem;height:1.8rem;border-radius:50%}.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;justify-content:space-between;align-items:center;padding:.6rem 0}.modal .mask{position:fixed;width:100vw;height:100vh;left:0;top:0;background:rgba(0,0,0,.3)}.radio-group2{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid #e2e2e2}.radio-group2 .radio{cursor:pointer;background:transparent;padding:.4rem 1rem;border-left:1px solid #e2e2e2;color:#9ca1a4;font-size:1.2rem}.radio-group2 .radio:first-child{border-left:none}.radio-group2 .active{background:#e2e2e2;color:gray}.radio-group2.isNight{border:1px solid #454847}.radio-group2.isNight .radio{border-left:1px solid #454847;color:#fff}.radio-group2.isNight .active{background:#31475e}.pop-confirm{position:relative;display:inline-flex;justify-content:center}.tip{position:fixed;background:black;color:#fff;max-width:10rem;padding:.7rem 1rem;border-radius:.5rem;transform:translate(-50%);z-index:999}input{height:3rem;outline:unset;border:1px solid #e1e1e1;padding:0 .5rem;border-radius:5px;box-sizing:border-box}.isNight .wrapper[data-v-2c468bc2]{background:#22303f!important}.isNight .wrapper .title[data-v-2c468bc2],.isNight .wrapper .option-title[data-v-2c468bc2],.isNight .wrapper .option>span[data-v-2c468bc2]{color:#a9a9a9}.isNight .wrapper .notice[data-v-2c468bc2]{color:gray!important}.setting-modal .wrapper[data-v-2c468bc2]{z-index:9;background:#f1f1f1;border-radius:.8rem;font-size:1.4rem;padding:2rem;max-height:80vh;max-width:80vw;overflow:auto}.setting-modal .wrapper .sub-title[data-v-2c468bc2]{color:gray;font-size:1.4rem}.setting-modal .wrapper .option-title[data-v-2c468bc2]{text-align:start;font-size:1.6rem;font-weight:700;margin-top:1.5rem}.setting-modal .wrapper .body[data-v-2c468bc2]{display:flex;gap:3rem}.setting-modal .wrapper .body .option-list[data-v-2c468bc2]{width:40rem}.setting-modal .wrapper .notice[data-v-2c468bc2]{font-size:12px;padding-left:3rem;text-align:left}.setting-modal .wrapper .notice a[data-v-2c468bc2]{color:#00f}.pop-confirm-content[data-v-8df5d12b]{position:fixed;background:white;padding:1.5rem;box-shadow:0 0 12px #0003;border-radius:.4rem;transform:translate(-50%,calc(-100% - 1rem));z-index:999}.pop-confirm-content .text[data-v-8df5d12b]{color:#000;text-align:start;font-size:1.4rem;width:15rem;min-width:15rem}.pop-confirm-content .options[data-v-8df5d12b]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem;font-size:1rem}.pop-confirm-content .options div[data-v-8df5d12b]{cursor:pointer}.pop-confirm-content .options .main[data-v-8df5d12b]{color:gray;background:#e2e2e2;padding:.3rem .8rem;border-radius:.2rem}.point[data-v-810a119b]{margin-left:1rem;font-size:1.2rem;min-width:4rem;border-radius:.4rem 0 0 .4rem;display:flex;align-items:center;flex-direction:row!important;padding:0!important}.point .up[data-v-810a119b]{display:flex;flex-direction:column;align-items:center;justify-content:center}.point .num[data-v-810a119b]{margin-left:.2rem;font-weight:700;color:#000;user-select:none}.point svg[data-v-810a119b]{width:2rem;padding:.4rem;border-radius:.2rem}.point svg[data-v-810a119b]:hover{background:#e5e5e5}.point svg.disabled[data-v-810a119b]{cursor:not-allowed}.point svg.disabled[data-v-810a119b]:hover{background:unset!important}.Author[data-v-d8c00e09]{display:flex;align-items:center;justify-content:space-between;font-size:1.2rem;position:relative;margin-bottom:.4rem}.Author.expand[data-v-d8c00e09]{margin-bottom:0}.Author .Author-left[data-v-d8c00e09]{display:flex;align-items:center;max-width:90%}.Author .Author-left .username[data-v-d8c00e09]{font-size:1.4rem;margin-right:1rem}.Author .Author-left .expand-icon[data-v-d8c00e09]{cursor:pointer;margin-right:.8rem;width:2rem;height:2rem;transform:rotate(90deg)}.Author .Author-left .avatar[data-v-d8c00e09]{margin-right:1rem;display:flex}.Author .Author-left .avatar img[data-v-d8c00e09]{width:3.4rem;height:3.4rem;border-radius:.3rem}.Author .Author-left .texts[data-v-d8c00e09]{flex:1}.Author .Author-left .op[data-v-d8c00e09]{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 .mod[data-v-d8c00e09]{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 .Author-left .my-tag[data-v-d8c00e09]{font-size:1.4rem;color:red;margin-left:1rem}.Author .Author-left .my-tag:hover .remove[data-v-d8c00e09]{display:inline}.Author .Author-left .my-tag .remove[data-v-d8c00e09]{cursor:pointer;margin-left:.5rem;display:none}.Author .Author-left .add-tag[data-v-d8c00e09]{font-size:2.5rem;transform:translateY(.2rem);line-height:1rem;display:inline-block;margin-left:1rem;cursor:pointer;display:none}.Author:hover .add-tag[data-v-d8c00e09]{display:inline-block}.Author .Author-right[data-v-d8c00e09]{position:absolute;right:0;display:flex;align-items:center}.Author .Author-right .toolbar[data-v-d8c00e09]{display:flex;align-items:center;color:#929596;opacity:0}.Author .Author-right .toolbar[data-v-d8c00e09]:hover{background:white;opacity:1}.Author .Author-right .floor[data-v-d8c00e09]{margin-left:1rem;font-size:1.2rem;line-height:1rem;border-radius:1rem;display:inline-block;background-color:#f0f0f0;color:#ccc;padding:.2rem .5rem;cursor:default}.Author .Author-right .isDev[data-v-d8c00e09]{color:#000!important}.post-editor-wrapper[data-v-48f028d5]{width:100%;box-sizing:border-box;position:relative;overflow:hidden;transition:all .3s}.post-editor-wrapper.reply-post .post-editor[data-v-48f028d5]{border:1px solid #e2e2e2;border-radius:.4rem}.post-editor-wrapper.reply-post.isFocus .post-editor[data-v-48f028d5]{border:1px solid #968b8b}.post-editor-wrapper.reply-comment[data-v-48f028d5]{border:1px solid #e2e2e2;border-radius:.4rem;overflow:hidden}.post-editor-wrapper.reply-comment.isFocus[data-v-48f028d5]{border:1px solid #968b8b}.post-editor-wrapper.reply-comment .toolbar[data-v-48f028d5]{background:#f6f7f8}.post-editor-wrapper .post-editor[data-v-48f028d5]{transition:border .3s;width:100%;max-width:100%;padding:.6rem 1.4rem;box-sizing:border-box;border:none;outline:none;font-family:Avenir,Helvetica,Arial,sans-serif;font-size:1.4rem;min-height:13rem;resize:none}.post-editor-wrapper .toolbar[data-v-48f028d5]{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-48f028d5]{display:flex;gap:1rem}.post-editor-wrapper .toolbar .left svg[data-v-48f028d5]{cursor:pointer}.post-editor-wrapper .toolbar .left .upload input[data-v-48f028d5]{cursor:pointer;position:absolute;width:20px;height:20px;opacity:0}.post-editor-wrapper .toolbar span[data-v-48f028d5]{color:gray;font-size:1.3rem}.post-editor-wrapper .get-cursor[data-v-48f028d5]{transition:border .3s;width:100%;max-width:100%;padding:.6rem 1.4rem;box-sizing:border-box;border:none;outline:none;font-family:Avenir,Helvetica,Arial,sans-serif;font-size:1.4rem;min-height:13rem;resize:none;position:absolute;top:0;z-index:-100}.post-editor-wrapper .emoticon-pack[data-v-48f028d5]{z-index:999999999;border-radius:1rem;padding:1rem;width:31rem;height:30rem;overflow:overlay;background:white;border:1px solid #e2e8f0;box-shadow:0 9px 24px -3px #0000000f,0 4px 8px -1px #0000001f;position:fixed;bottom:11rem;left:14rem}.post-editor-wrapper .emoticon-pack i[data-v-48f028d5]{cursor:pointer;position:absolute;right:2rem;font-size:2rem;color:#e2e2e2}.post-editor-wrapper .emoticon-pack .list[data-v-48f028d5]{margin:1rem 0}.post-editor-wrapper .emoticon-pack img[data-v-48f028d5]{cursor:pointer;width:3rem;height:3rem;padding:.5rem}.post-editor-wrapper .emoticon-pack span[data-v-48f028d5]{display:inline-block;cursor:pointer;font-size:2.3rem;padding:.5rem}.isNight .emoticon-pack[data-v-48f028d5]{background:#18222d;border:1px solid #737373}.v-enter-active[data-v-a77c3d96],.v-leave-active[data-v-a77c3d96]{transition:opacity .3s ease}.v-enter-from[data-v-a77c3d96],.v-leave-to[data-v-a77c3d96]{opacity:0}.username[data-v-a77c3d96]{font-weight:700;font-size:1.4rem;margin-right:1rem}.op[data-v-a77c3d96]{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-a77c3d96]{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-a77c3d96]{font-size:1.4rem;color:red;margin-left:1rem}.my-tag:hover .remove[data-v-a77c3d96]{display:inline}.my-tag .remove[data-v-a77c3d96]{cursor:pointer;margin-left:.5rem;display:none}.floor[data-v-a77c3d96]{margin-left:1rem;font-size:1.2rem;line-height:1rem;border-radius:1rem;display:inline-block;background-color:#f0f0f0;color:#ccc;padding:.2rem .5rem;cursor:default}html[data-v-a77c3d96],body[data-v-a77c3d96]{font-size:62.5%}.flex[data-v-a77c3d96]{display:flex;align-items:center;justify-content:space-between}.flex-end[data-v-a77c3d96]{justify-content:flex-end}.flex-center[data-v-a77c3d96]{justify-content:center}.p1[data-v-a77c3d96]{padding:1rem}.p0[data-v-a77c3d96]{padding:0!important}.post-author[data-v-a77c3d96]{display:flex;align-items:center;position:relative;color:#ccc!important}.post-author>.username[data-v-a77c3d96]{font-size:1.2rem}.sticky[data-v-a77c3d96]{position:sticky;bottom:0}.sticky[stuck][data-v-a77c3d96]{box-shadow:0 2px 20px #00000059}a[data-v-a77c3d96]{color:#778087;text-decoration:none;cursor:pointer}a[data-v-a77c3d96]:hover{text-decoration:underline}.base-loading[data-v-a77c3d96]{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle-a77c3d96 infinite 1s linear}.loading-c[data-v-a77c3d96]{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle-a77c3d96 infinite 1s linear;width:3rem;height:3rem}.loading-b[data-v-a77c3d96]{border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle-a77c3d96 infinite 1s linear;border-color:#ffffff rgba(178,177,177,.2) rgba(178,177,177,.2) rgba(178,177,177,.2);width:3rem;height:3rem}@keyframes circle-a77c3d96{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.button[data-v-a77c3d96]{cursor:pointer;padding:.4rem 2.4rem;border-radius:5px;display:inline-flex;justify-content:center;align-items:center;font-weight:700;font-size:1.2rem;color:#fff;background:#40a9ff;border:1px solid #40a9ff;user-select:none}.button[data-v-a77c3d96]:hover{opacity:.9}.button.info[data-v-a77c3d96]{color:#000;border:1px solid #40a9ff;background:white}.button.gray[data-v-a77c3d96]{color:#f5f5f5;border:1px solid #b6b6b6;background:#b6b6b6}.button.light[data-v-a77c3d96]{color:gray;border:1px solid #e2e2e2;background:#e2e2e2}.button[data-v-a77c3d96]:before{content:" ";border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle-a77c3d96 infinite 1s linear;border-color:#fff transparent transparent transparent;width:1rem;height:1rem;margin-right:1rem;display:none}.button.loading[data-v-a77c3d96]{cursor:not-allowed;opacity:.5}.button.loading[data-v-a77c3d96]:before{display:block}.button.disabled[data-v-a77c3d96]{cursor:not-allowed;color:#c6c6c6;background:#8d8d8d;border:1px solid transparent}.button.isNight[data-v-a77c3d96]{color:#c6c6c6;background:#2b4054;border:1px solid transparent}.tool[data-v-a77c3d96]{position:relative;margin-left:1rem;display:flex;align-items:center;font-size:1.2rem;font-weight:700;border-radius:.2rem;cursor:pointer;height:3rem;padding:0 .5rem}.tool[data-v-a77c3d96]:before{content:" ";border:2px solid;border-color:#000 #00000033 #00000033 #00000033;border-radius:100%;animation:circle-a77c3d96 infinite 1s linear;border-color:transparent #929596 #929596 #929596;width:1rem;height:1rem;margin-left:1rem;display:none}.tool.loading[data-v-a77c3d96]{cursor:not-allowed;opacity:.5}.tool.loading[data-v-a77c3d96]:before{display:block}.tool.loading[data-v-a77c3d96]:hover{background:unset}.tool>svg[data-v-a77c3d96]{width:1.6rem!important;height:1.6rem!important;margin-right:.4rem;box-sizing:border-box;border-radius:.2rem}.tool[data-v-a77c3d96]:hover{background:#e8e8e8}.tool.no-hover[data-v-a77c3d96]{cursor:default}.tool.no-hover[data-v-a77c3d96]:hover{background:unset}.my-node[data-v-a77c3d96]{border-radius:.2rem;padding:.4rem;font-size:1rem;color:#999;background:#f5f5f5;cursor:pointer}.my-node[data-v-a77c3d96]:hover{text-decoration:none;background:#e2e2e2}.msgs[data-v-a77c3d96]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.msg[data-v-a77c3d96]{cursor:default;margin-bottom:2rem;background:white;display:flex;color:#000;font-size:1.4rem;box-sizing:border-box;border-radius:.4rem;box-shadow:0 0 1rem 1px silver}.msg.success .left[data-v-a77c3d96]{background:#40a9ff}.msg.warning .left[data-v-a77c3d96]{background:#c8c002}.msg.error .left[data-v-a77c3d96]{background:red}.msg .left[data-v-a77c3d96]{border-radius:.4rem 0 0 .4rem;display:flex;align-items:center;background:#40a9ff}.msg .left svg[data-v-a77c3d96]{margin:0 .3rem;cursor:pointer}.msg .right[data-v-a77c3d96]{flex:1;padding:1rem 2rem;display:flex;justify-content:space-between;align-items:center}.line[data-v-a77c3d96]{border-bottom:1px solid #e2e2e2}.my-box[data-v-a77c3d96]{box-shadow:0 2px 3px #0000001a;border-radius:.4rem;background:white;margin-bottom:2rem;width:100%;overflow:hidden;box-sizing:border-box}.my-cell[data-v-a77c3d96]{padding:1rem;font-size:1.4rem;line-height:150%;text-align:left;border-bottom:1px solid #e2e2e2}.f14[data-v-a77c3d96]{font-size:1.4rem}.switch[data-v-a77c3d96]{width:4.5rem;height:2rem;border-radius:2rem;position:relative;display:flex;align-items:center;transition:all .3s}.switch.light[data-v-a77c3d96]{border:1px solid #e2e2e2}.switch.light.active[data-v-a77c3d96]{background:#e2e2e2}.switch.light.active[data-v-a77c3d96]:before{right:.2rem;background:white}.switch.light[data-v-a77c3d96]:before{background:#e2e2e2}.switch.gray[data-v-a77c3d96]{border:1px solid #ccc}.switch.gray.active[data-v-a77c3d96]{background:#ccc}.switch.gray.active[data-v-a77c3d96]:before{right:.2rem;background:white}.switch.gray[data-v-a77c3d96]:before{background:#ccc}.switch.isNight[data-v-a77c3d96]{border:1px solid #31475e}.switch.isNight.active[data-v-a77c3d96]{background:#31475e}.switch.isNight.active[data-v-a77c3d96]:before{right:.2rem;background:gray}.switch.isNight[data-v-a77c3d96]:before{background:#31475e}.switch[data-v-a77c3d96]:before{position:absolute;content:" ";transition:all .3s;right:calc(100% - 2rem);width:1.8rem;height:1.8rem;border-radius:50%}.modal[data-v-a77c3d96]{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-a77c3d96]{font-size:2.4rem;margin-bottom:1rem;text-align:center}.modal .option[data-v-a77c3d96]{display:flex;justify-content:space-between;align-items:center;padding:.6rem 0}.modal .mask[data-v-a77c3d96]{position:fixed;width:100vw;height:100vh;left:0;top:0;background:rgba(0,0,0,.3)}.radio-group2[data-v-a77c3d96]{display:inline-flex;border-radius:.5rem;overflow:hidden;border:1px solid #e2e2e2}.radio-group2 .radio[data-v-a77c3d96]{cursor:pointer;background:transparent;padding:.4rem 1rem;border-left:1px solid #e2e2e2;color:#9ca1a4;font-size:1.2rem}.radio-group2 .radio[data-v-a77c3d96]:first-child{border-left:none}.radio-group2 .active[data-v-a77c3d96]{background:#e2e2e2;color:gray}.radio-group2.isNight[data-v-a77c3d96]{border:1px solid #454847}.radio-group2.isNight .radio[data-v-a77c3d96]{border-left:1px solid #454847;color:#fff}.radio-group2.isNight .active[data-v-a77c3d96]{background:#31475e}.pop-confirm[data-v-a77c3d96]{position:relative;display:inline-flex;justify-content:center}.tip[data-v-a77c3d96]{position:fixed;background:black;color:#fff;max-width:10rem;padding:.7rem 1rem;border-radius:.5rem;transform:translate(-50%);z-index:999}input[data-v-a77c3d96]{height:3rem;outline:unset;border:1px solid #e1e1e1;padding:0 .5rem;border-radius:5px;box-sizing:border-box}.html-wrapper[data-v-a77c3d96]{position:relative}.html-wrapper .mask[data-v-a77c3d96]{max-height:90rem;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 80%,transparent)}.html-wrapper .expand[data-v-a77c3d96]{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-a0031aa2]{width:100%;box-sizing:border-box;margin-top:1rem}.comment.isLevelOne[data-v-a0031aa2]{border-bottom:1px solid #ececec;padding:1rem;margin-top:0}.comment.ding[data-v-a0031aa2]{background:rgba(255,255,0,.3)!important}.comment .comment-content-w .more[data-v-a0031aa2]{text-align:center;margin:2rem 0}.comment .comment-content[data-v-a0031aa2]{display:flex;position:relative}.comment .comment-content .expand-line[data-v-a0031aa2]{cursor:pointer;width:3rem;min-width:3rem;position:relative}.comment .comment-content .expand-line[data-v-a0031aa2]:after{position:absolute;left:calc(60% - 1px);content:" ";height:100%;width:0;border-right:1px solid #ececec}.comment .comment-content .expand-line[data-v-a0031aa2]:hover:after{border-right:2px solid #0079D3}.comment .comment-content .right[data-v-a0031aa2]{flex:1;width:calc(100% - 3rem)}.comment .comment-content .right .w[data-v-a0031aa2]{padding-left:1.7rem}.comment .comment-content .right .w .post-editor-wrapper[data-v-a0031aa2]{margin-top:1rem}.wrong-wrapper[data-v-a0031aa2]{font-size:1.4rem;margin-bottom:1rem}.wrong-wrapper span[data-v-a0031aa2]{cursor:pointer}.wrong-wrapper .del-line[data-v-a0031aa2]{text-decoration:line-through}.wrong-wrapper .wrong-icon[data-v-a0031aa2]{margin-left:.5rem}.wrong-wrapper .warning[data-v-a0031aa2]{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-07fa3ae8]{display:flex;align-items:center;color:#929596}.comment[data-v-3eb530b9]{width:100%;box-sizing:border-box;display:flex;gap:1rem;padding:1rem;border-bottom:1px solid #e2e2e2}.comment .avatar[data-v-3eb530b9]{display:flex}.comment .avatar img[data-v-3eb530b9]{width:3.8rem;height:3.8rem;border-radius:.3rem}.comment .comment-body[data-v-3eb530b9]{flex:1;display:flex;flex-direction:column}.comment .comment-body .texts[data-v-3eb530b9]{display:flex;align-items:center}.comment .comment-body .reply_content[data-v-3eb530b9]{margin-top:1rem;max-width:calc(100% - 5rem)}.comment .isRight[data-v-3eb530b9]{align-items:flex-end}.comment .isRight .op[data-v-3eb530b9],.comment .isRight .mod[data-v-3eb530b9],.comment .isRight .username[data-v-3eb530b9]{margin:0 0 0 1rem}.comment .Author-right[data-v-3eb530b9]{display:flex;flex-direction:column;align-items:center}.comment .Author-right .floor[data-v-3eb530b9]{margin-left:0}.comment .Author-right .jump[data-v-3eb530b9]{color:#929596;margin-left:0}.comment .point[data-v-3eb530b9]{margin:0 .5rem;font-size:1.4rem;display:flex;gap:.5rem;align-items:center;font-weight:700;color:#000}.sticky{position:sticky;bottom:-2px;z-index:2}.sticky[stuck]{box-shadow:0 2px 20px #00000059!important}.Post[data-v-4038172d]{position:unset!important;background:transparent!important;overflow:unset!important}.Post .main[data-v-4038172d]{background:transparent!important;padding:unset!important;width:100%!important}.Post .close-btn[data-v-4038172d]{display:none}.post-detail[data-v-4038172d]{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.isNight[data-v-4038172d]{background:rgba(46,47,48,.8)}.post-detail.isNight .main[data-v-4038172d]{background:#22303f}.post-detail.isNight .main .toolbar-wrapper[data-v-4038172d]{border-top:unset!important}.post-detail.isNight .main .button.gray[data-v-4038172d]{background:#18222d!important;border:1px solid #18222d!important}.post-detail.isNight .main .relationReply[data-v-4038172d]{color:#fff}.post-detail.isNight .main .relationReply .comments[data-v-4038172d],.post-detail.isNight .main .relationReply .my-cell[data-v-4038172d]{background:#18222d}.post-detail.isNight .main .relationReply .comment[data-v-4038172d]{border-bottom:1px solid #22303f}.post-detail.isNight .main .my-box[data-v-4038172d]{color:#fff;background:#18222d}.post-detail.isNight .main .my-box .title[data-v-4038172d],.post-detail.isNight .main .my-box .content[data-v-4038172d]{color:#d1d5d9!important}.post-detail.isNight .main .my-box .base-info[data-v-4038172d],.post-detail.isNight .main .my-box .content[data-v-4038172d]{border:1px solid #22303f!important}.post-detail.isNight .main[data-v-4038172d] .subtle .fade{color:#b2c3d4!important}.post-detail.isNight .main[data-v-4038172d] .subtle .topic_content{color:#d1d5d9!important}.post-detail.isNight .main .my-cell[data-v-4038172d]{border-bottom:1px solid #22303f!important}.post-detail.isNight .main[data-v-4038172d] .isLevelOne{border-bottom:1px solid #22303f}.post-detail.isNight .main[data-v-4038172d] .comment .expand-line:after{border-right:1px solid #22303f!important}.post-detail.isNight .main[data-v-4038172d] .comment .expand-line:hover:after{border-right:2px solid #0079D3!important}.post-detail.isNight .main[data-v-4038172d] .comment .comment-content .w>.text{color:#d1d5d9!important}.post-detail.isNight .main[data-v-4038172d] .Author-right .toolbar:hover{background:#18222d!important}.post-detail.isNight .main[data-v-4038172d] .Author-right .tool{background:#22303f!important}.post-detail.isNight .main[data-v-4038172d] .point svg:hover{background:#22303f}.post-detail.isNight .main[data-v-4038172d] .point .num{color:#d1d5d9!important}.post-detail.isNight .main[data-v-4038172d] .floor{background:#393f4e!important;color:#d1d5d9!important}.post-detail.isNight .main .editor-wrapper[data-v-4038172d]{background:#393f4e!important}.post-detail.isNight .main[data-v-4038172d] .post-editor-wrapper .post-editor{background:#18222d;border:transparent;color:#fff}.post-detail.isNight .main[data-v-4038172d] .post-editor-wrapper .toolbar{background:#393f4e!important}.post-detail.isNight .main .call-list[data-v-4038172d]{background:#22303f}.post-detail.isNight .main .call-list .call-item[data-v-4038172d]{border-top:1px solid #18222d}.post-detail.isNight .main .call-list .call-item .select[data-v-4038172d],.post-detail.isNight .main .call-list .call-item[data-v-4038172d]:hover,.post-detail.isNight .main .call-list .call-item.select[data-v-4038172d]{background-color:#393f4e;text-decoration:none}.post-detail.isNight .main .scroll-to[data-v-4038172d],.post-detail.isNight .main .close-btn[data-v-4038172d],.post-detail.isNight .main .scroll-top[data-v-4038172d],.post-detail.isNight .main .top-reply[data-v-4038172d]{color:#9caec7}.post-detail .main[data-v-4038172d]{display:flex;justify-content:flex-end;padding:3rem 8rem 15rem;background:#e2e2e2;position:relative}.post-detail .main .main-wrapper[data-v-4038172d]{width:77rem;padding-bottom:2rem;display:flex;flex-direction:column;align-items:center;position:relative}.post-detail .main .main-wrapper .post-wrapper .toolbar-wrapper[data-v-4038172d]{border-top:1px solid #e2e2e2;height:4rem;padding-left:.6rem;display:flex;align-items:center}.post-detail .main .main-wrapper .editor-wrapper .float[data-v-4038172d]{margin-right:2rem}.post-detail .main .main-wrapper .editor-wrapper .w[data-v-4038172d]{padding:1.2rem}.post-detail .main .main-wrapper .comment-wrapper .comments[data-v-4038172d]{width:100%;box-sizing:border-box}.post-detail .main .main-wrapper .loading-wrapper[data-v-4038172d]{height:20rem;display:flex;justify-content:center;align-items:center}.post-detail .main .main-wrapper #no-comments-yet[data-v-4038172d]{color:#a9a9a9;font-weight:700;text-align:center;width:100%;margin-bottom:2rem;box-sizing:border-box}.post-detail .main .relationReply[data-v-4038172d]{position:fixed;width:25vw;top:6.5rem;bottom:15rem;z-index:99;transform:translate(calc(100% + 2rem));font-size:2rem;overflow:hidden}.post-detail .main .relationReply .my-cell[data-v-4038172d]{background:white;border-radius:.5rem .5rem 0 0}.post-detail .main .relationReply .comments[data-v-4038172d]{max-height:calc(100% - 4.2rem);overflow:auto;background:white;border-radius:0 0 .5rem .5rem}.post-detail .main .call-list[data-v-4038172d]{z-index:9;position:absolute;top:12rem;border:1px solid #ccc;background-color:#fff;box-shadow:0 5px 15px #0000001a;overflow:hidden;max-height:30rem;min-width:8rem;box-sizing:content-box}.post-detail .main .call-list .call-item[data-v-4038172d]{border-top:1px solid #ccc;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-4038172d],.post-detail .main .call-list .call-item[data-v-4038172d]:hover,.post-detail .main .call-list .call-item.select[data-v-4038172d]{background-color:#f0f0f0;text-decoration:none}.post-detail .main .call-list .call-item[data-v-4038172d]:nth-child(1){border-top:1px solid transparent}@media screen and (max-width: 1500px){.post-detail .main-wrapper[data-v-4038172d]{width:65vw!important}}@media screen and (max-width: 1280px){.post-detail .main-wrapper[data-v-4038172d]{width:75vw!important}}.post-detail .scroll-top[data-v-4038172d]{position:fixed;bottom:10rem;z-index:99;padding:.6rem .2rem;width:3.5rem;transform:translate(6rem);font-size:2rem;background:#f1f1f1;border:none;color:#a9a9a9}.post-detail .scroll-to[data-v-4038172d]{position:fixed;bottom:10rem;z-index:99;padding:.6rem .2rem;width:3.5rem;transform:translate(6rem);font-size:2rem;background:#f1f1f1;border:none;color:#a9a9a9;bottom:15rem;display:flex;flex-direction:column}.post-detail .scroll-to input[data-v-4038172d]{margin-top:.5rem;height:2rem;width:3.3rem;font-size:1.4rem;text-align:center;color:gray}.post-detail .read-notice[data-v-4038172d]{display:flex;align-items:center;color:gray}.post-detail .read-notice .jump[data-v-4038172d]{background:#f1f1f1;color:gray;padding:.3rem 1rem;border-radius:.4rem;margin:0 1rem;cursor:pointer}.post-detail .close-btn[data-v-4038172d]{color:#b6b6b6;cursor:pointer;position:fixed;top:3rem;transform:translate(4rem);font-size:2rem}.post-detail .top-reply[data-v-4038172d]{color:#e2e2e2;cursor:pointer;font-size:2rem;display:flex}.post-detail .top-reply i[data-v-4038172d]{padding:0 1rem}.isNight[data-v-19fe372d]{background:#22303f!important;color:#ccc!important}.base64_tooltip[data-v-19fe372d]{box-shadow:0 3px 6px -4px #0000001f,0 6px 16px #00000014,0 9px 28px 8px #0000000d;background:white;min-height:2.2rem;max-width:20rem;padding:.8rem;position:fixed;z-index:9998;display:flex;align-items:center;border-radius:.5rem;cursor:pointer;line-break:anywhere;font-size:1.4rem;color:#000}.base64_tooltip svg[data-v-19fe372d]{margin-left:1rem;min-width:1.8rem}.base64_tooltip .button[data-v-19fe372d]{margin-top:1rem;margin-left:2rem}.isNight .wrapper[data-v-b28a2e5e]{background:#22303f!important}.isNight .wrapper .title[data-v-b28a2e5e]{color:gray}.isNight .wrapper .option[data-v-b28a2e5e]{color:#fff!important}.isNight .wrapper .option span[data-v-b28a2e5e]{color:gray!important}.isNight .wrapper .white[data-v-b28a2e5e]{color:#fff!important}.tag-modal .wrapper[data-v-b28a2e5e]{z-index:9;background:#f1f1f1;border-radius:.8rem;font-size:1.4rem;padding:2rem 6rem 4rem;width:25rem}.tag-modal .wrapper .btns[data-v-b28a2e5e]{margin-top:1.5rem;display:flex;justify-content:flex-end;align-items:center;gap:1.5rem;font-size:1rem}.tag-modal .wrapper .btns div[data-v-b28a2e5e]{cursor:pointer}.tag-modal .wrapper .btns .main[data-v-b28a2e5e]{color:gray;background:#e2e2e2;padding:.5rem 1.2rem;border-radius:.4rem}.msgs[data-v-95974c3e]{position:fixed;margin-left:calc(50% - 25rem);width:50rem;z-index:9999;bottom:0;left:0;right:0}.isNight .open-post[data-v-f9a9d2e9],.isNight .nav[data-v-f9a9d2e9]{color:#fff;background:#18222d;border-bottom:1px solid #22303f}.card[data-v-f9a9d2e9]{border-radius:0 0 .4rem .4rem;overflow:hidden}.nav[data-v-f9a9d2e9]{font-size:1.4rem;background:white;padding:1rem;border-bottom:1px solid #e2e2e2} ');
  21.  
  22. (function (vue) {
  23. 'use strict';
  24.  
  25. var PageType = /* @__PURE__ */ ((PageType2) => {
  26. PageType2["Home"] = "Home";
  27. PageType2["Node"] = "Node";
  28. PageType2["Post"] = "Post";
  29. return PageType2;
  30. })(PageType || {});
  31. const _export_sfc = (sfc, props) => {
  32. const target = sfc.__vccOpts || sfc;
  33. for (const [key, val] of props) {
  34. target[key] = val;
  35. }
  36. return target;
  37. };
  38. const _sfc_main$f = {
  39. name: "Setting",
  40. inject: ["isNight"],
  41. props: {
  42. modelValue: {
  43. type: Object,
  44. default() {
  45. return {};
  46. }
  47. },
  48. show: {
  49. type: Boolean,
  50. default() {
  51. return false;
  52. }
  53. }
  54. },
  55. data() {
  56. return {
  57. config: window.clone(this.modelValue)
  58. };
  59. },
  60. watch: {
  61. config: {
  62. handler(n) {
  63. n.topReplyLoveMinCount = Math.trunc(n.topReplyLoveMinCount);
  64. if (n.topReplyLoveMinCount < 0) {
  65. n.topReplyLoveMinCount = 1;
  66. }
  67. this.$emit("update:modelValue", n);
  68. },
  69. deep: true
  70. }
  71. },
  72. created() {
  73. }
  74. };
  75. const _withScopeId$8 = (n) => (vue.pushScopeId("data-v-2c468bc2"), n = n(), vue.popScopeId(), n);
  76. const _hoisted_1$f = { class: "wrapper" };
  77. const _hoisted_2$d = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 脚本设置 ", -1));
  78. const _hoisted_3$a = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "sub-title" }, " 设置自动保存到本地,下次打开依然生效 ", -1));
  79. const _hoisted_4$8 = { class: "body" };
  80. const _hoisted_5$7 = { class: "option-list" };
  81. const _hoisted_6$7 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "option-title" }, "列表:", -1));
  82. const _hoisted_7$6 = { class: "option" };
  83. const _hoisted_8$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "列表帖子展示方式:", -1));
  84. const _hoisted_9$6 = { class: "option" };
  85. const _hoisted_10$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "列表hover时显示预览按钮:", -1));
  86. const _hoisted_11$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 此项需要刷新页面才能生效 ", -1));
  87. const _hoisted_12$6 = { class: "option" };
  88. const _hoisted_13$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "点击列表的帖子,打开详情弹框 :", -1));
  89. const _hoisted_14$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 若关闭此项,点击列表的帖子时,不会打开弹框,会跳转网页 ", -1));
  90. const _hoisted_15$6 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "option-title" }, "帖子:", -1));
  91. const _hoisted_16$4 = { class: "option" };
  92. const _hoisted_17$4 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "回复展示方式:", -1));
  93. const _hoisted_18$4 = { class: "option" };
  94. const _hoisted_19$4 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "单独打开帖子时默认显示楼中楼 :", -1));
  95. const _hoisted_20$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 单独打开这种地址 https://v2ex.com/t/xxxx 时,是否默认显示楼中楼 ", -1));
  96. const _hoisted_21$3 = { class: "option" };
  97. const _hoisted_22$3 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "点击左右两侧透明处关闭帖子详情弹框:", -1));
  98. const _hoisted_23$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "option-title" }, "点赞:", -1));
  99. const _hoisted_24$3 = { class: "option" };
  100. const _hoisted_25$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "显示高赞回复:", -1));
  101. const _hoisted_26$2 = { class: "option" };
  102. const _hoisted_27$2 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "最多显示多少个高赞回复:", -1));
  103. const _hoisted_28$1 = { class: "option" };
  104. const _hoisted_29$1 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "最少需要多少赞才能被判定为高赞:", -1));
  105. const _hoisted_30$1 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "option-title" }, "记忆阅读:", -1));
  106. const _hoisted_31$1 = { class: "option" };
  107. const _hoisted_32$1 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "记录上次阅读楼层(误差1层左右):", -1));
  108. const _hoisted_33$1 = { class: "option" };
  109. const _hoisted_34$1 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "打开帖子自动跳转到上次阅读楼层:", -1));
  110. const _hoisted_35$1 = { class: "option-list" };
  111. const _hoisted_36$1 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "option-title" }, "其他:", -1));
  112. const _hoisted_37 = { class: "option" };
  113. const _hoisted_38 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "显示工具栏:", -1));
  114. const _hoisted_39 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, [
  115. /* @__PURE__ */ vue.createTextVNode(" 关闭此项会隐藏以下三个工具栏 "),
  116. /* @__PURE__ */ vue.createElementVNode("div", null, " 1. 首页”卡片/表格“ "),
  117. /* @__PURE__ */ vue.createElementVNode("div", null, " 2. 详情页”楼中楼/只看楼主/感谢/V2原版“ "),
  118. /* @__PURE__ */ vue.createElementVNode("div", null, " 3. 单独打开帖子时”点击显示楼中楼“ ")
  119. ], -1));
  120. const _hoisted_40 = { class: "option" };
  121. const _hoisted_41 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "新标签页打开链接 :", -1));
  122. const _hoisted_42 = { class: "option" };
  123. const _hoisted_43 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户打标签(跨平台,数据保存在自己的记事本):", -1));
  124. const _hoisted_44 = { class: "option" };
  125. const _hoisted_45 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "正文超长自动折叠:", -1));
  126. const _hoisted_46 = { class: "option" };
  127. const _hoisted_47 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "划词显示Base64解码框:", -1));
  128. const _hoisted_48 = { class: "option" };
  129. const _hoisted_49 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "使用 SOV2EX 搜索:", -1));
  130. const _hoisted_50 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 此项需要刷新页面才能生效 ", -1));
  131. const _hoisted_51 = { class: "option" };
  132. const _hoisted_52 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "帖子宽度:", -1));
  133. const _hoisted_53 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, [
  134. /* @__PURE__ */ vue.createTextVNode(" 默认为77rem。接受合法的width值: "),
  135. /* @__PURE__ */ vue.createElementVNode("a", {
  136. href: "https://vue3js.cn/interview/css/em_px_rem_vh_vw.html#%E4%BA%8C%E3%80%81%E5%8D%95%E4%BD%8D",
  137. target: "_blank"
  138. }, "rem、px、vw、vh"),
  139. /* @__PURE__ */ vue.createTextVNode("。 vw代表屏幕百分比,如想要屏幕的66%,请填写66vw ")
  140. ], -1));
  141. const _hoisted_54 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 提示:此项设置以后,单独打开详情页时会出现帖子突然变宽(窄)的问题,暂时无解 ", -1));
  142. const _hoisted_55 = { class: "option" };
  143. const _hoisted_56 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "自动签到:", -1));
  144. const _hoisted_57 = { class: "option" };
  145. const _hoisted_58 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "自定义背景:", -1));
  146. const _hoisted_59 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, [
  147. /* @__PURE__ */ vue.createTextVNode(" 接受一个合法的css color值:例如"),
  148. /* @__PURE__ */ vue.createElementVNode("a", {
  149. href: "https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value",
  150. target: "_blank"
  151. }, "red、#ffffff、rgb(222,222,22)"),
  152. /* @__PURE__ */ vue.createTextVNode("等等。 没图片时的背景默认为 #e2e2e2。 ")
  153. ], -1));
  154. const _hoisted_60 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " 此项需要刷新页面才能生效 ", -1));
  155. const _hoisted_61 = { class: "option" };
  156. const _hoisted_62 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("span", null, "收藏时提醒添加到书签:", -1));
  157. const _hoisted_63 = /* @__PURE__ */ _withScopeId$8(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "notice" }, " V站的帐号一旦被封了,就无法登录(不可用)了,账号里的收藏也就看不到了 ", -1));
  158. function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
  159. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  160. default: vue.withCtx(() => [
  161. $props.show ? (vue.openBlock(), vue.createElementBlock("div", {
  162. key: 0,
  163. class: vue.normalizeClass(["setting-modal modal", { isNight: $options.isNight }])
  164. }, [
  165. vue.createElementVNode("div", {
  166. class: "mask",
  167. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:show", false))
  168. }),
  169. vue.createElementVNode("div", _hoisted_1$f, [
  170. _hoisted_2$d,
  171. _hoisted_3$a,
  172. vue.createElementVNode("div", _hoisted_4$8, [
  173. vue.createElementVNode("div", _hoisted_5$7, [
  174. _hoisted_6$7,
  175. vue.createElementVNode("div", _hoisted_7$6, [
  176. _hoisted_8$6,
  177. vue.createElementVNode("div", {
  178. class: vue.normalizeClass(["radio-group2", { isNight: $options.isNight }])
  179. }, [
  180. vue.createElementVNode("div", {
  181. class: vue.normalizeClass(["radio", $data.config.viewType === "table" ? "active" : ""]),
  182. onClick: _cache[1] || (_cache[1] = ($event) => $data.config.viewType = "table")
  183. }, "表格 ", 2),
  184. vue.createElementVNode("div", {
  185. class: vue.normalizeClass(["radio", $data.config.viewType === "card" ? "active" : ""]),
  186. onClick: _cache[2] || (_cache[2] = ($event) => $data.config.viewType = "card")
  187. }, "卡片 ", 2)
  188. ], 2)
  189. ]),
  190. vue.createElementVNode("div", _hoisted_9$6, [
  191. _hoisted_10$6,
  192. vue.createElementVNode("div", {
  193. class: vue.normalizeClass(["switch gray", { active: $data.config.showPreviewBtn, isNight: $options.isNight }]),
  194. onClick: _cache[3] || (_cache[3] = ($event) => $data.config.showPreviewBtn = !$data.config.showPreviewBtn)
  195. }, null, 2)
  196. ]),
  197. _hoisted_11$6,
  198. vue.createElementVNode("div", _hoisted_12$6, [
  199. _hoisted_13$6,
  200. vue.createElementVNode("div", {
  201. class: vue.normalizeClass(["switch gray", { active: $data.config.clickPostItemOpenDetail, isNight: $options.isNight }]),
  202. onClick: _cache[4] || (_cache[4] = ($event) => $data.config.clickPostItemOpenDetail = !$data.config.clickPostItemOpenDetail)
  203. }, null, 2)
  204. ]),
  205. _hoisted_14$6,
  206. _hoisted_15$6,
  207. vue.createElementVNode("div", _hoisted_16$4, [
  208. _hoisted_17$4,
  209. vue.createElementVNode("div", {
  210. class: vue.normalizeClass(["radio-group2", { isNight: $options.isNight }])
  211. }, [
  212. vue.createElementVNode("div", {
  213. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === 0 ? "active" : ""]),
  214. onClick: _cache[5] || (_cache[5] = ($event) => $data.config.commentDisplayType = 0)
  215. }, "楼中楼 ", 2),
  216. vue.createElementVNode("div", {
  217. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === 1 ? "active" : ""]),
  218. onClick: _cache[6] || (_cache[6] = ($event) => $data.config.commentDisplayType = 1)
  219. }, "感谢 ", 2),
  220. vue.createElementVNode("div", {
  221. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === 3 ? "active" : ""]),
  222. onClick: _cache[7] || (_cache[7] = ($event) => $data.config.commentDisplayType = 3)
  223. }, "只看楼主 ", 2),
  224. vue.createElementVNode("div", {
  225. class: vue.normalizeClass(["radio", $data.config.commentDisplayType === 2 ? "active" : ""]),
  226. onClick: _cache[8] || (_cache[8] = ($event) => $data.config.commentDisplayType = 2)
  227. }, "V2原版 ", 2)
  228. ], 2)
  229. ]),
  230. vue.createElementVNode("div", _hoisted_18$4, [
  231. _hoisted_19$4,
  232. vue.createElementVNode("div", {
  233. class: vue.normalizeClass(["switch gray", { active: $data.config.autoOpenDetail, isNight: $options.isNight }]),
  234. onClick: _cache[9] || (_cache[9] = ($event) => $data.config.autoOpenDetail = !$data.config.autoOpenDetail)
  235. }, null, 2)
  236. ]),
  237. _hoisted_20$3,
  238. vue.createElementVNode("div", _hoisted_21$3, [
  239. _hoisted_22$3,
  240. vue.createElementVNode("div", {
  241. class: vue.normalizeClass(["switch gray", { active: $data.config.closePostDetailBySpace, isNight: $options.isNight }]),
  242. onClick: _cache[10] || (_cache[10] = ($event) => $data.config.closePostDetailBySpace = !$data.config.closePostDetailBySpace)
  243. }, null, 2)
  244. ]),
  245. _hoisted_23$2,
  246. vue.createElementVNode("div", _hoisted_24$3, [
  247. _hoisted_25$2,
  248. vue.createElementVNode("div", {
  249. class: vue.normalizeClass(["switch gray", { active: $data.config.showTopReply, isNight: $options.isNight }]),
  250. onClick: _cache[11] || (_cache[11] = ($event) => $data.config.showTopReply = !$data.config.showTopReply)
  251. }, null, 2)
  252. ]),
  253. vue.createElementVNode("div", _hoisted_26$2, [
  254. _hoisted_27$2,
  255. vue.withDirectives(vue.createElementVNode("input", {
  256. type: "number",
  257. min: "1",
  258. "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => $data.config.topReplyCount = $event)
  259. }, null, 512), [
  260. [vue.vModelText, $data.config.topReplyCount]
  261. ])
  262. ]),
  263. vue.createElementVNode("div", _hoisted_28$1, [
  264. _hoisted_29$1,
  265. vue.withDirectives(vue.createElementVNode("input", {
  266. type: "number",
  267. min: "1",
  268. "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => $data.config.topReplyLoveMinCount = $event)
  269. }, null, 512), [
  270. [vue.vModelText, $data.config.topReplyLoveMinCount]
  271. ])
  272. ]),
  273. _hoisted_30$1,
  274. vue.createElementVNode("div", _hoisted_31$1, [
  275. _hoisted_32$1,
  276. vue.createElementVNode("div", {
  277. class: vue.normalizeClass(["switch gray", { active: $data.config.rememberLastReadFloor, isNight: $options.isNight }]),
  278. onClick: _cache[14] || (_cache[14] = ($event) => {
  279. $data.config.rememberLastReadFloor = !$data.config.rememberLastReadFloor;
  280. $data.config.autoJumpLastReadFloor = false;
  281. })
  282. }, null, 2)
  283. ]),
  284. vue.createElementVNode("div", _hoisted_33$1, [
  285. _hoisted_34$1,
  286. vue.createElementVNode("div", {
  287. class: vue.normalizeClass(["switch gray", { active: $data.config.autoJumpLastReadFloor, isNight: $options.isNight }]),
  288. onClick: _cache[15] || (_cache[15] = ($event) => $data.config.autoJumpLastReadFloor = !$data.config.autoJumpLastReadFloor)
  289. }, null, 2)
  290. ])
  291. ]),
  292. vue.createElementVNode("div", _hoisted_35$1, [
  293. _hoisted_36$1,
  294. vue.createElementVNode("div", _hoisted_37, [
  295. _hoisted_38,
  296. vue.createElementVNode("div", {
  297. class: vue.normalizeClass(["switch gray", { active: $data.config.showToolbar, isNight: $options.isNight }]),
  298. onClick: _cache[16] || (_cache[16] = ($event) => $data.config.showToolbar = !$data.config.showToolbar)
  299. }, null, 2)
  300. ]),
  301. _hoisted_39,
  302. vue.createElementVNode("div", _hoisted_40, [
  303. _hoisted_41,
  304. vue.createElementVNode("div", {
  305. class: vue.normalizeClass(["switch gray", { active: $data.config.newTabOpen, isNight: $options.isNight }]),
  306. onClick: _cache[17] || (_cache[17] = ($event) => {
  307. $data.config.newTabOpen = !$data.config.newTabOpen;
  308. $data.config.clickPostItemOpenDetail = !$data.config.newTabOpen;
  309. })
  310. }, null, 2)
  311. ]),
  312. vue.createElementVNode("div", _hoisted_42, [
  313. _hoisted_43,
  314. vue.createElementVNode("div", {
  315. class: vue.normalizeClass(["switch gray", { active: $data.config.openTag, isNight: $options.isNight }]),
  316. onClick: _cache[18] || (_cache[18] = ($event) => $data.config.openTag = !$data.config.openTag)
  317. }, null, 2)
  318. ]),
  319. vue.createElementVNode("div", _hoisted_44, [
  320. _hoisted_45,
  321. vue.createElementVNode("div", {
  322. class: vue.normalizeClass(["switch gray", { active: $data.config.contentAutoCollapse, isNight: $options.isNight }]),
  323. onClick: _cache[19] || (_cache[19] = ($event) => $data.config.contentAutoCollapse = !$data.config.contentAutoCollapse)
  324. }, null, 2)
  325. ]),
  326. vue.createElementVNode("div", _hoisted_46, [
  327. _hoisted_47,
  328. vue.createElementVNode("div", {
  329. class: vue.normalizeClass(["switch gray", { active: $data.config.base64, isNight: $options.isNight }]),
  330. onClick: _cache[20] || (_cache[20] = ($event) => $data.config.base64 = !$data.config.base64)
  331. }, null, 2)
  332. ]),
  333. vue.createElementVNode("div", _hoisted_48, [
  334. _hoisted_49,
  335. vue.createElementVNode("div", {
  336. class: vue.normalizeClass(["switch gray", { active: $data.config.sov2ex, isNight: $options.isNight }]),
  337. onClick: _cache[21] || (_cache[21] = ($event) => $data.config.sov2ex = !$data.config.sov2ex)
  338. }, null, 2)
  339. ]),
  340. _hoisted_50,
  341. vue.createElementVNode("div", _hoisted_51, [
  342. _hoisted_52,
  343. vue.withDirectives(vue.createElementVNode("input", {
  344. type: "text",
  345. "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => $data.config.postWidth = $event)
  346. }, null, 512), [
  347. [vue.vModelText, $data.config.postWidth]
  348. ])
  349. ]),
  350. _hoisted_53,
  351. _hoisted_54,
  352. vue.createElementVNode("div", _hoisted_55, [
  353. _hoisted_56,
  354. vue.createElementVNode("div", {
  355. class: vue.normalizeClass(["switch gray", { active: $data.config.autoSignin, isNight: $options.isNight }]),
  356. onClick: _cache[23] || (_cache[23] = ($event) => $data.config.autoSignin = !$data.config.autoSignin)
  357. }, null, 2)
  358. ]),
  359. vue.createElementVNode("div", _hoisted_57, [
  360. _hoisted_58,
  361. vue.withDirectives(vue.createElementVNode("input", {
  362. type: "text",
  363. "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => $data.config.customBgColor = $event)
  364. }, null, 512), [
  365. [vue.vModelText, $data.config.customBgColor]
  366. ])
  367. ]),
  368. _hoisted_59,
  369. _hoisted_60,
  370. vue.createElementVNode("div", _hoisted_61, [
  371. _hoisted_62,
  372. vue.createElementVNode("div", {
  373. class: vue.normalizeClass(["switch gray", { active: $data.config.collectBrowserNotice, isNight: $options.isNight }]),
  374. onClick: _cache[25] || (_cache[25] = ($event) => $data.config.collectBrowserNotice = !$data.config.collectBrowserNotice)
  375. }, null, 2)
  376. ]),
  377. _hoisted_63
  378. ])
  379. ])
  380. ])
  381. ], 2)) : vue.createCommentVNode("", true)
  382. ]),
  383. _: 1
  384. });
  385. }
  386. const Setting = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["render", _sfc_render$9], ["__scopeId", "data-v-2c468bc2"]]);
  387. const eventBus = {
  388. eventMap: /* @__PURE__ */ new Map(),
  389. on(eventType, cb) {
  390. let cbs = this.eventMap.get(eventType);
  391. if (cbs) {
  392. cbs.push(cb);
  393. } else {
  394. cbs = [cb];
  395. }
  396. this.eventMap.set(eventType, cbs);
  397. },
  398. emit(eventType, val) {
  399. let cbs = this.eventMap.get(eventType);
  400. if (cbs) {
  401. cbs.map((cb) => cb(val));
  402. }
  403. },
  404. off(eventType) {
  405. let cbs = this.eventMap.has(eventType);
  406. if (cbs) {
  407. this.eventMap.delete(eventType);
  408. }
  409. },
  410. clear() {
  411. this.eventMap = /* @__PURE__ */ new Map();
  412. }
  413. };
  414. const CMD = {
  415. SHOW_TOOLTIP: "SHOW_TOOLTIP",
  416. SHOW_MSG: "SHOW_MSG",
  417. SET_CALL: "SET_CALL",
  418. SHOW_CALL: "SHOW_CALL",
  419. REFRESH_ONCE: "REFRESH_ONCE",
  420. ADD_REPLY: "ADD_REPLY",
  421. IGNORE: "IGNORE",
  422. MERGE: "MERGE",
  423. REMOVE: "REMOVE",
  424. CHANGE_COMMENT_THANK: "CHANGE_COMMENT_THANK",
  425. CHANGE_POST_THANK: "CHANGE_POST_THANK",
  426. ADD_TAG: "ADD_TAG",
  427. REMOVE_TAG: "REMOVE_TAG",
  428. RELATION_REPLY: "RELATION_REPLY",
  429. JUMP: "JUMP",
  430. ADD_READ: "ADD_READ"
  431. };
  432. const _sfc_main$e = {
  433. name: "PopConfirm",
  434. props: {
  435. title: {
  436. type: String,
  437. default() {
  438. return "";
  439. }
  440. },
  441. disabled: {
  442. type: Boolean,
  443. default() {
  444. return false;
  445. }
  446. }
  447. },
  448. data() {
  449. return {
  450. show: false
  451. };
  452. },
  453. methods: {
  454. showPop(e) {
  455. if (this.disabled)
  456. return;
  457. let rect = e.target.getBoundingClientRect();
  458. this.show = true;
  459. vue.nextTick(() => {
  460. this.$refs.tip.style.top = rect.top + "px";
  461. this.$refs.tip.style.left = rect.left + rect.width / 2 - 50 + "px";
  462. });
  463. },
  464. confirm() {
  465. this.show = false;
  466. this.$emit("confirm");
  467. }
  468. }
  469. };
  470. const _hoisted_1$e = { class: "pop-confirm" };
  471. const _hoisted_2$c = {
  472. key: 0,
  473. ref: "tip",
  474. class: "pop-confirm-content"
  475. };
  476. const _hoisted_3$9 = { class: "text" };
  477. const _hoisted_4$7 = { class: "options" };
  478. function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
  479. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$e, [
  480. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  481. vue.createVNode(vue.Transition, null, {
  482. default: vue.withCtx(() => [
  483. $data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$c, [
  484. vue.createElementVNode("div", _hoisted_3$9, vue.toDisplayString($props.title), 1),
  485. vue.createElementVNode("div", _hoisted_4$7, [
  486. vue.createElementVNode("div", {
  487. onClick: _cache[0] || (_cache[0] = ($event) => $data.show = false)
  488. }, "取消"),
  489. vue.createElementVNode("div", {
  490. class: "main",
  491. onClick: _cache[1] || (_cache[1] = (...args) => $options.confirm && $options.confirm(...args))
  492. }, "确认")
  493. ])
  494. ], 512)) : vue.createCommentVNode("", true)
  495. ]),
  496. _: 1
  497. })
  498. ])),
  499. vue.createElementVNode("span", {
  500. onClick: _cache[2] || (_cache[2] = (...args) => $options.showPop && $options.showPop(...args))
  501. }, [
  502. vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
  503. ])
  504. ]);
  505. }
  506. const PopConfirm = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$8], ["__scopeId", "data-v-8df5d12b"]]);
  507. const loveColor = "rgb(224,42,42)";
  508. const _sfc_main$d = {
  509. name: "Point",
  510. components: { PopConfirm },
  511. inject: ["post", "isLogin"],
  512. props: {
  513. item: {
  514. type: Object,
  515. default() {
  516. return {};
  517. }
  518. },
  519. full: {
  520. type: Boolean,
  521. default() {
  522. return true;
  523. }
  524. },
  525. apiUrl: ""
  526. },
  527. computed: {
  528. disabled() {
  529. return this.item.username === window.user.username || this.item.isThanked || !this.isLogin;
  530. }
  531. },
  532. methods: {
  533. getColor() {
  534. if (this.item.isThanked)
  535. return loveColor;
  536. return this.full ? loveColor : "#929596";
  537. },
  538. getIsFull() {
  539. if (this.item.isThanked)
  540. return loveColor;
  541. return this.full ? loveColor : "none";
  542. },
  543. thankError() {
  544. if (this.item.username === window.user.username) {
  545. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "不能感谢自己" });
  546. }
  547. if (this.item.isThanked) {
  548. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "已经感谢过了" });
  549. }
  550. if (!this.isLogin) {
  551. return eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录(不可用)!" });
  552. }
  553. },
  554. async thank() {
  555. this.$emit("addThank");
  556. let url = `${window.baseUrl}/thank/${this.apiUrl}?once=${this.post.once}`;
  557. $.post(url).then((res) => {
  558. if (!res.success) {
  559. this.$emit("recallThank");
  560. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: res.message });
  561. }
  562. eventBus.emit(CMD.REFRESH_ONCE, res.once);
  563. }, (err) => {
  564. this.$emit("recallThank");
  565. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "感谢失败" });
  566. eventBus.emit(CMD.REFRESH_ONCE);
  567. });
  568. }
  569. }
  570. };
  571. const _hoisted_1$d = { class: "point" };
  572. const _hoisted_2$b = ["fill", "stroke"];
  573. const _hoisted_3$8 = { class: "num" };
  574. function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
  575. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  576. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$d, [
  577. vue.createVNode(_component_PopConfirm, {
  578. disabled: $options.disabled,
  579. title: `确认花费 10 个铜币向 @${$props.item.username} 的这条回复发送感谢?`,
  580. onConfirm: $options.thank
  581. }, {
  582. default: vue.withCtx(() => [
  583. vue.createElementVNode("div", {
  584. class: "up",
  585. onClick: _cache[0] || (_cache[0] = (...args) => $options.thankError && $options.thankError(...args))
  586. }, [
  587. (vue.openBlock(), vue.createElementBlock("svg", {
  588. class: vue.normalizeClass({ disabled: $options.disabled }),
  589. width: "19",
  590. height: "19",
  591. viewBox: "0 0 48 48",
  592. fill: "none",
  593. xmlns: "http://www.w3.org/2000/svg"
  594. }, [
  595. vue.createElementVNode("path", {
  596. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  597. fill: $options.getIsFull(),
  598. stroke: $options.getColor(),
  599. "stroke-width": "2",
  600. "stroke-linecap": "round",
  601. "stroke-linejoin": "round"
  602. }, null, 8, _hoisted_2$b)
  603. ], 2))
  604. ])
  605. ]),
  606. _: 1
  607. }, 8, ["disabled", "title", "onConfirm"]),
  608. vue.createElementVNode("div", _hoisted_3$8, vue.toDisplayString($props.item.thankCount ? $props.item.thankCount : "感谢"), 1)
  609. ]);
  610. }
  611. const Point = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$7], ["__scopeId", "data-v-810a119b"]]);
  612. const _sfc_main$c = {
  613. name: "Author",
  614. components: { PopConfirm, Point },
  615. inject: ["isLogin", "tags", "config"],
  616. props: {
  617. modelValue: false,
  618. comment: {
  619. type: Object,
  620. default() {
  621. return {};
  622. }
  623. },
  624. type: {
  625. type: String,
  626. default() {
  627. return "list";
  628. }
  629. }
  630. },
  631. computed: {
  632. isDev() {
  633. return false;
  634. },
  635. pointInfo() {
  636. return {
  637. isThanked: this.comment.isThanked,
  638. thankCount: this.comment.thankCount,
  639. username: this.comment.username
  640. };
  641. },
  642. myTags() {
  643. return this.tags[this.comment.username] ?? [];
  644. },
  645. context() {
  646. return this.comment.replyUsers.length;
  647. }
  648. },
  649. methods: {
  650. jump() {
  651. eventBus.emit(CMD.JUMP, this.comment.floor);
  652. },
  653. showRelationReply() {
  654. if (!this.comment.replyUsers.length) {
  655. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "该回复无上下文" });
  656. return;
  657. }
  658. eventBus.emit(CMD.RELATION_REPLY, {
  659. left: this.comment.replyUsers,
  660. right: this.comment.username,
  661. rightFloor: this.comment.floor
  662. });
  663. },
  664. addTag() {
  665. eventBus.emit(CMD.ADD_TAG, this.comment.username);
  666. },
  667. removeTag(tag) {
  668. eventBus.emit(CMD.REMOVE_TAG, { username: this.comment.username, tag });
  669. },
  670. checkIsLogin(emitName = "") {
  671. if (!this.isLogin) {
  672. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录(不可用)!" });
  673. return false;
  674. }
  675. this.$emit(emitName);
  676. return true;
  677. },
  678. addThank() {
  679. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "add" });
  680. },
  681. recallThank() {
  682. eventBus.emit(CMD.CHANGE_COMMENT_THANK, { id: this.comment.id, type: "recall" });
  683. }
  684. }
  685. };
  686. const _withScopeId$7 = (n) => (vue.pushScopeId("data-v-d8c00e09"), n = n(), vue.popScopeId(), n);
  687. const _hoisted_1$c = { class: "Author-left" };
  688. const _hoisted_2$a = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("path", {
  689. d: "M22 42H6V26",
  690. stroke: "#177EC9",
  691. "stroke-width": "4",
  692. "stroke-linecap": "round",
  693. "stroke-linejoin": "round"
  694. }, null, -1));
  695. const _hoisted_3$7 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("path", {
  696. d: "M26 6H42V22",
  697. stroke: "#177EC9",
  698. "stroke-width": "4",
  699. "stroke-linecap": "round",
  700. "stroke-linejoin": "round"
  701. }, null, -1));
  702. const _hoisted_4$6 = [
  703. _hoisted_2$a,
  704. _hoisted_3$7
  705. ];
  706. const _hoisted_5$6 = ["href"];
  707. const _hoisted_6$6 = ["src"];
  708. const _hoisted_7$5 = { class: "texts" };
  709. const _hoisted_8$5 = ["href"];
  710. const _hoisted_9$5 = {
  711. key: 0,
  712. class: "op"
  713. };
  714. const _hoisted_10$5 = {
  715. key: 1,
  716. class: "mod"
  717. };
  718. const _hoisted_11$5 = { class: "ago" };
  719. const _hoisted_12$5 = { class: "my-tag" };
  720. const _hoisted_13$5 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  721. const _hoisted_14$5 = ["onClick"];
  722. const _hoisted_15$5 = { class: "Author-right" };
  723. const _hoisted_16$3 = {
  724. key: 0,
  725. class: "toolbar"
  726. };
  727. const _hoisted_17$3 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "tool" }, [
  728. /* @__PURE__ */ vue.createElementVNode("span", null, "隐藏")
  729. ], -1));
  730. const _hoisted_18$3 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上下文", -1));
  731. const _hoisted_19$3 = [
  732. _hoisted_18$3
  733. ];
  734. const _hoisted_20$2 = /* @__PURE__ */ _withScopeId$7(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  735. const _hoisted_21$2 = [
  736. _hoisted_20$2
  737. ];
  738. const _hoisted_22$2 = /* @__PURE__ */ vue.createStaticVNode('<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-d8c00e09><path d="M4 6H44V36H29L24 41L19 36H4V6Z" fill="none" stroke="#929596" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-d8c00e09></path><path d="M23 21H25.0025" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-d8c00e09></path><path d="M33.001 21H34.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-d8c00e09></path><path d="M13.001 21H14.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-d8c00e09></path></svg><span data-v-d8c00e09>回复</span>', 2);
  739. const _hoisted_24$2 = [
  740. _hoisted_22$2
  741. ];
  742. function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
  743. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  744. const _component_Point = vue.resolveComponent("Point");
  745. return vue.openBlock(), vue.createElementBlock("div", {
  746. class: vue.normalizeClass(["Author", { expand: !$props.modelValue }])
  747. }, [
  748. vue.createElementVNode("div", _hoisted_1$c, [
  749. !$props.modelValue ? (vue.openBlock(), vue.createElementBlock("svg", {
  750. key: 0,
  751. class: "expand-icon",
  752. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", true)),
  753. width: "24",
  754. height: "24",
  755. viewBox: "0 0 48 48",
  756. fill: "none",
  757. xmlns: "http://www.w3.org/2000/svg"
  758. }, _hoisted_4$6)) : vue.createCommentVNode("", true),
  759. vue.createElementVNode("a", {
  760. class: "avatar",
  761. href: `/member/${$props.comment.username}`
  762. }, [
  763. vue.createElementVNode("img", {
  764. src: $props.comment.avatar,
  765. alt: ""
  766. }, null, 8, _hoisted_6$6)
  767. ], 8, _hoisted_5$6),
  768. vue.createElementVNode("span", _hoisted_7$5, [
  769. vue.createElementVNode("strong", null, [
  770. vue.createElementVNode("a", {
  771. href: `/member/${$props.comment.username}`,
  772. class: "username"
  773. }, vue.toDisplayString($props.comment.username), 9, _hoisted_8$5)
  774. ]),
  775. $props.comment.isOp ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$5, "OP")) : vue.createCommentVNode("", true),
  776. $props.comment.isMod ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$5, "MOD")) : vue.createCommentVNode("", true),
  777. vue.createElementVNode("span", _hoisted_11$5, vue.toDisplayString($props.comment.date), 1),
  778. $options.isLogin && $options.config.openTag ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 2 }, [
  779. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.myTags, (i) => {
  780. return vue.openBlock(), vue.createElementBlock("span", _hoisted_12$5, [
  781. _hoisted_13$5,
  782. vue.createElementVNode("span", null, vue.toDisplayString(i), 1),
  783. vue.createElementVNode("i", {
  784. class: "fa fa-trash-o remove",
  785. onClick: ($event) => $options.removeTag(i)
  786. }, null, 8, _hoisted_14$5)
  787. ]);
  788. }), 256)),
  789. vue.createElementVNode("span", {
  790. class: "add-tag ago",
  791. onClick: _cache[1] || (_cache[1] = (...args) => $options.addTag && $options.addTag(...args)),
  792. title: "添加标签"
  793. }, "+")
  794. ], 64)) : vue.createCommentVNode("", true)
  795. ])
  796. ]),
  797. vue.createElementVNode("div", _hoisted_15$5, [
  798. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_16$3, [
  799. vue.createVNode(_component_PopConfirm, {
  800. title: "确认隐藏这条回复?",
  801. onConfirm: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("hide"))
  802. }, {
  803. default: vue.withCtx(() => [
  804. _hoisted_17$3
  805. ]),
  806. _: 1
  807. }),
  808. $options.context ? (vue.openBlock(), vue.createElementBlock("div", {
  809. key: 0,
  810. class: "tool",
  811. onClick: _cache[3] || (_cache[3] = (...args) => $options.showRelationReply && $options.showRelationReply(...args))
  812. }, _hoisted_19$3)) : vue.createCommentVNode("", true),
  813. $props.type === "top" ? (vue.openBlock(), vue.createElementBlock("div", {
  814. key: 1,
  815. class: "tool",
  816. onClick: _cache[4] || (_cache[4] = (...args) => $options.jump && $options.jump(...args))
  817. }, _hoisted_21$2)) : vue.createCommentVNode("", true),
  818. vue.createElementVNode("div", {
  819. class: "tool",
  820. onClick: _cache[5] || (_cache[5] = ($event) => $options.checkIsLogin("reply"))
  821. }, _hoisted_24$2),
  822. vue.withDirectives(vue.createVNode(_component_Point, {
  823. item: $options.pointInfo,
  824. onAddThank: $options.addThank,
  825. onRecallThank: $options.recallThank,
  826. "api-url": "reply/" + $props.comment.id
  827. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  828. [vue.vShow, !$props.comment.thankCount]
  829. ])
  830. ])) : vue.createCommentVNode("", true),
  831. vue.withDirectives(vue.createVNode(_component_Point, {
  832. item: $options.pointInfo,
  833. onAddThank: $options.addThank,
  834. onRecallThank: $options.recallThank,
  835. "api-url": "reply/" + $props.comment.id
  836. }, null, 8, ["item", "onAddThank", "onRecallThank", "api-url"]), [
  837. [vue.vShow, $props.comment.thankCount]
  838. ]),
  839. vue.createElementVNode("div", {
  840. class: vue.normalizeClass(["floor", { isDev: $options.isDev }])
  841. }, vue.toDisplayString($options.isDev ? `a${$props.comment.floor}-` : $props.comment.floor), 3)
  842. ])
  843. ], 2);
  844. }
  845. const Author = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["render", _sfc_render$6], ["__scopeId", "data-v-d8c00e09"]]);
  846. const _withScopeId$6 = (n) => (vue.pushScopeId("data-v-48f028d5"), n = n(), vue.popScopeId(), n);
  847. const _hoisted_1$b = { class: "get-cursor" };
  848. const _hoisted_2$9 = ["innerHTML"];
  849. const _hoisted_3$6 = { class: "toolbar" };
  850. const _hoisted_4$5 = { class: "left" };
  851. const _hoisted_5$5 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("path", {
  852. d: "M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z",
  853. fill: "none",
  854. stroke: "#929596",
  855. "stroke-width": "2",
  856. "stroke-linejoin": "round"
  857. }, null, -1));
  858. const _hoisted_6$5 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("path", {
  859. d: "M24 35C29 35 31 31 31 31H17C17 31 19 35 24 35Z",
  860. stroke: "#929596",
  861. "stroke-width": "2",
  862. "stroke-linecap": "round",
  863. "stroke-linejoin": "round"
  864. }, null, -1));
  865. const _hoisted_7$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("path", {
  866. d: "M31 18V22",
  867. stroke: "#929596",
  868. "stroke-width": "2",
  869. "stroke-linecap": "round",
  870. "stroke-linejoin": "round"
  871. }, null, -1));
  872. const _hoisted_8$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("path", {
  873. d: "M17 18V22",
  874. stroke: "#929596",
  875. "stroke-width": "2",
  876. "stroke-linecap": "round",
  877. "stroke-linejoin": "round"
  878. }, null, -1));
  879. const _hoisted_9$4 = [
  880. _hoisted_5$5,
  881. _hoisted_6$5,
  882. _hoisted_7$4,
  883. _hoisted_8$4
  884. ];
  885. const _hoisted_10$4 = { class: "upload" };
  886. const _hoisted_11$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  887. width: "20",
  888. height: "20",
  889. viewBox: "0 0 48 48",
  890. fill: "none",
  891. xmlns: "http://www.w3.org/2000/svg"
  892. }, [
  893. /* @__PURE__ */ vue.createElementVNode("path", {
  894. "fill-rule": "evenodd",
  895. "clip-rule": "evenodd",
  896. d: "M5 10C5 8.89543 5.89543 8 7 8L41 8C42.1046 8 43 8.89543 43 10V38C43 39.1046 42.1046 40 41 40H7C5.89543 40 5 39.1046 5 38V10Z",
  897. stroke: "#929596",
  898. "stroke-width": "2",
  899. "stroke-linecap": "round",
  900. "stroke-linejoin": "round"
  901. }),
  902. /* @__PURE__ */ vue.createElementVNode("path", {
  903. "fill-rule": "evenodd",
  904. "clip-rule": "evenodd",
  905. d: "M14.5 18C15.3284 18 16 17.3284 16 16.5C16 15.6716 15.3284 15 14.5 15C13.6716 15 13 15.6716 13 16.5C13 17.3284 13.6716 18 14.5 18Z",
  906. stroke: "#929596",
  907. "stroke-width": "2",
  908. "stroke-linecap": "round",
  909. "stroke-linejoin": "round"
  910. }),
  911. /* @__PURE__ */ vue.createElementVNode("path", {
  912. d: "M15 24L20 28L26 21L43 34V38C43 39.1046 42.1046 40 41 40H7C5.89543 40 5 39.1046 5 38V34L15 24Z",
  913. fill: "none",
  914. stroke: "#929596",
  915. "stroke-width": "2",
  916. "stroke-linejoin": "round"
  917. })
  918. ], -1));
  919. const _hoisted_12$4 = { key: 0 };
  920. const _hoisted_13$4 = /* @__PURE__ */ _withScopeId$6(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, "经典表情", -1));
  921. const _hoisted_14$4 = { class: "list" };
  922. const _hoisted_15$4 = ["src", "onClick"];
  923. const _hoisted_16$2 = { class: "emoji" };
  924. const _hoisted_17$2 = { class: "title" };
  925. const _hoisted_18$2 = { class: "list" };
  926. const _hoisted_19$2 = ["onClick"];
  927. const _sfc_main$b = {
  928. __name: "PostEditor",
  929. props: {
  930. replyUser: null,
  931. replyFloor: null,
  932. useType: {
  933. type: String,
  934. default() {
  935. return "reply-comment";
  936. }
  937. }
  938. },
  939. emits: ["close"],
  940. setup(__props, { expose, emit: emits }) {
  941. const props = __props;
  942. const { replyUser, replyFloor, useType } = props;
  943. const replyInfo = replyUser ? `@${replyUser} #${replyFloor} ` : "";
  944. const post = vue.inject("post");
  945. vue.inject("show");
  946. const isNight = vue.inject("isNight");
  947. vue.inject("pageType");
  948. const allReplyUsers = vue.inject("allReplyUsers");
  949. let isFocus = vue.ref(false);
  950. const loading = vue.ref(false);
  951. const uploadLoading = vue.ref(false);
  952. const isShowEmoticons = vue.ref(false);
  953. const editorId = vue.ref("editorId_" + Date.now());
  954. const content = vue.ref(replyInfo);
  955. const txtRef = vue.ref(null);
  956. const cursorRef = vue.ref(null);
  957. const emoticonsRef = vue.ref(null);
  958. const none = vue.ref('<span style="white-space:pre-wrap;"> </span>');
  959. const emojiEmoticons = [
  960. {
  961. title: "小黄脸",
  962. list: [
  963. "😀",
  964. "😁",
  965. "😂",
  966. "🤣",
  967. "😅",
  968. "😊",
  969. "😋",
  970. "😘",
  971. "🥰",
  972. "😗",
  973. "🤩",
  974. "🤔",
  975. "🤨",
  976. "😐",
  977. "😑",
  978. "🙄",
  979. "😏",
  980. "😪",
  981. "😫",
  982. "🥱",
  983. "😜",
  984. "😒",
  985. "😔",
  986. "😨",
  987. "😰",
  988. "😱",
  989. "🥵",
  990. "😡",
  991. "🥳",
  992. "🥺",
  993. "🤭",
  994. "🧐",
  995. "😎",
  996. "🤓",
  997. "😭",
  998. "🤑",
  999. "🤮"
  1000. ]
  1001. },
  1002. {
  1003. title: "手势",
  1004. list: [
  1005. "🙋",
  1006. "🙎",
  1007. "🙅",
  1008. "🙇",
  1009. "🤷",
  1010. "🤏",
  1011. "👉",
  1012. "✌️",
  1013. "🤘",
  1014. "🤙",
  1015. "👌",
  1016. "🤌",
  1017. "👍",
  1018. "👎",
  1019. "👋",
  1020. "🤝",
  1021. "🙏",
  1022. "👏"
  1023. ]
  1024. },
  1025. {
  1026. title: "庆祝",
  1027. list: ["✨", "🎉", "🎊"]
  1028. },
  1029. {
  1030. title: "其他",
  1031. list: ["👻", "🤡", "🐔", "👀", "💩", "🐴", "🦄", "🐧", "🐶", "🐒", "🙈", "🙉", "🙊", "🐵"]
  1032. }
  1033. ];
  1034. const classicsEmoticons = [
  1035. {
  1036. name: "[狗头]",
  1037. low: "https://i.imgur.com/nQIIqnv.png",
  1038. high: "https://i.imgur.com/0icl60r.png"
  1039. },
  1040. {
  1041. name: "[马]",
  1042. low: "https://i.imgur.com/5FyD9Un.png",
  1043. high: "https://i.imgur.com/ANFUX52.png"
  1044. },
  1045. {
  1046. name: "[不高兴]",
  1047. low: "https://i.imgur.com/cbIUvcG.png",
  1048. high: "https://i.imgur.com/i7O4v0O.png"
  1049. },
  1050. {
  1051. name: "[真棒]",
  1052. low: "https://i.imgur.com/IPG5yJO.png",
  1053. high: "https://i.imgur.com/mzefu0w.png"
  1054. },
  1055. {
  1056. name: "[疑问]",
  1057. low: "https://i.imgur.com/IqpiI7h.png",
  1058. high: "https://i.imgur.com/ygs7SFM.png"
  1059. },
  1060. {
  1061. name: "[笑眼]",
  1062. low: "https://i.imgur.com/PlO4jbB.png",
  1063. high: "https://i.imgur.com/zpGsuyY.png"
  1064. },
  1065. {
  1066. name: "[喷]",
  1067. low: "https://i.imgur.com/iN8x1Sm.png",
  1068. high: "https://i.imgur.com/d4g2dbf.png"
  1069. },
  1070. {
  1071. name: "[苦笑]",
  1072. low: "https://i.imgur.com/6gZe7Jg.png",
  1073. high: "https://i.imgur.com/NAfspZ1.png"
  1074. },
  1075. {
  1076. name: "[喝酒]",
  1077. low: "https://i.imgur.com/v7BAkoy.png",
  1078. high: "https://i.imgur.com/rVbSVak.png"
  1079. },
  1080. {
  1081. name: "[吃瓜]",
  1082. low: "https://i.imgur.com/SnluqXL.png",
  1083. high: "https://i.imgur.com/0L26og9.png"
  1084. },
  1085. {
  1086. name: "[捂脸]",
  1087. low: "https://i.imgur.com/Q3bcJJ9.png",
  1088. high: "https://i.imgur.com/qqBqgVm.png"
  1089. },
  1090. {
  1091. name: "[呕吐]",
  1092. low: "https://i.imgur.com/096Nc7O.png",
  1093. high: "https://i.imgur.com/AVFtmIl.png"
  1094. },
  1095. {
  1096. name: "[怒]",
  1097. low: "https://i.imgur.com/uGk6mIa.png",
  1098. high: "https://i.imgur.com/3YUDhdh.png"
  1099. },
  1100. {
  1101. name: "[衰]",
  1102. low: "https://i.imgur.com/WJXUrLF.png",
  1103. high: "https://i.imgur.com/XffE6gu.png"
  1104. },
  1105. {
  1106. name: "[合十]",
  1107. low: "https://i.imgur.com/dibCTJG.png",
  1108. high: "https://i.imgur.com/T4rJVee.png"
  1109. },
  1110. {
  1111. name: "[赞]",
  1112. low: "https://i.imgur.com/yVg4qEx.png",
  1113. high: "https://i.imgur.com/AoF5PLp.png"
  1114. },
  1115. {
  1116. name: "[踩]",
  1117. low: "https://i.imgur.com/mWjzsH1.png",
  1118. high: "https://i.imgur.com/1XYGfXj.png"
  1119. },
  1120. {
  1121. name: "[爱心]",
  1122. low: "https://i.imgur.com/edXjhvU.png",
  1123. high: "https://i.imgur.com/dND56oX.png"
  1124. },
  1125. {
  1126. name: "[心碎]",
  1127. low: "https://i.imgur.com/1krm1wx.png",
  1128. high: "https://i.imgur.com/RiUsPci.png"
  1129. }
  1130. ];
  1131. const imgurClientIdPool = [
  1132. "3107b9ef8b316f3",
  1133. "442b04f26eefc8a",
  1134. "59cfebe717c09e4",
  1135. "60605aad4a62882",
  1136. "6c65ab1d3f5452a",
  1137. "83e123737849aa9",
  1138. "9311f6be1c10160",
  1139. "c4a4a563f698595",
  1140. "81be04b9e4a08ce"
  1141. ];
  1142. expose({ content });
  1143. const editorClass = vue.computed(() => {
  1144. return [useType, isFocus.value ? "isFocus" : "", isNight.value ? "isNight" : ""];
  1145. });
  1146. const cursorHtml = vue.computed(() => {
  1147. var _a;
  1148. if (!txtRef.value || !content.value)
  1149. return "";
  1150. let index2 = ((_a = txtRef.value) == null ? void 0 : _a.selectionStart) || 0;
  1151. return content.value.substring(0, index2).replace(/</g, "<").replace(/>/g, ">").replace(/\n/g, "<br/>").replace(/\s/g, none.value);
  1152. });
  1153. const disabled = vue.computed(() => {
  1154. if (content.value) {
  1155. return content.value === replyInfo;
  1156. } else {
  1157. return true;
  1158. }
  1159. });
  1160. function drop(e) {
  1161. e.preventDefault();
  1162. upload(e.dataTransfer.files[0]);
  1163. }
  1164. async function upload(file) {
  1165. if (!file)
  1166. return;
  1167. if (uploadLoading.value)
  1168. return;
  1169. uploadLoading.value = true;
  1170. const formData = new FormData();
  1171. formData.append("image", file);
  1172. const randomIndex = Math.floor(Math.random() * imgurClientIdPool.length);
  1173. const clidenId = imgurClientIdPool[randomIndex];
  1174. const res = await fetch("https://api.imgur.com/3/upload", {
  1175. method: "POST",
  1176. headers: { Authorization: `Client-ID ${clidenId}` },
  1177. body: formData
  1178. });
  1179. uploadLoading.value = false;
  1180. if (res.ok) {
  1181. const resData = await res.json();
  1182. if (resData.success) {
  1183. return insert(resData.data.link + " ");
  1184. }
  1185. }
  1186. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "上传失败" });
  1187. }
  1188. async function submit() {
  1189. if (disabled.value || loading.value)
  1190. return;
  1191. loading.value = true;
  1192. let submit_content = content.value.replace(/\[((?!\[).)+\]/g, function(match) {
  1193. let item2 = classicsEmoticons.find((v) => v.name === match);
  1194. if (item2) {
  1195. return item2.low + " ";
  1196. }
  1197. return match;
  1198. });
  1199. let show_content = content.value.replace(/https?:\/\/(i\.)?imgur\.com\/((?!http).)+\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)/g, function(match) {
  1200. return `<img src="${match}" data-originUrl="${match}" data-notice="这个img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`;
  1201. });
  1202. show_content = show_content.replace(/\[((?!\[).)+\]/g, function(match) {
  1203. let item2 = classicsEmoticons.find((v) => v.name === match);
  1204. if (item2) {
  1205. return `<a target="_blank" href="${item2.low}" rel="nofollow noopener"><img
  1206. src="${item2.low}" class="embedded_image" rel="noreferrer">
  1207. </a>
  1208. `;
  1209. }
  1210. return match;
  1211. });
  1212. let matchUsers = show_content.match(/@([\w]+?[\s])/g);
  1213. if (matchUsers) {
  1214. matchUsers.map((i) => {
  1215. let username = i.replace("@", "").replace(" ", "");
  1216. show_content = show_content.replace(username, `<a href="/member/${username}">${username}</a>`);
  1217. });
  1218. }
  1219. let item = {
  1220. thankCount: 0,
  1221. isThanked: false,
  1222. isOp: post.value.username === window.user.username,
  1223. id: Date.now(),
  1224. username: window.user.username,
  1225. avatar: window.user.avatar,
  1226. date: "几秒前",
  1227. floor: post.value.replyCount + 1,
  1228. reply_content: show_content ?? "",
  1229. children: [],
  1230. replyUsers: replyUser ? [replyUser] : [],
  1231. replyFloor: replyFloor || -1,
  1232. level: useType === "reply-comment" ? 1 : 0
  1233. };
  1234. let url = `${window.baseUrl}/t/${post.value.id}`;
  1235. $.post(url, { content: submit_content, once: post.value.once }).then(
  1236. (res) => {
  1237. loading.value = false;
  1238. let r = res.search("你上一条回复的内容和这条相同");
  1239. if (r > -1)
  1240. return eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你上一条回复的内容和这条相同" });
  1241. r = res.search("请不要在每一个回复中都包括外链,这看起来像是在 spamming");
  1242. if (r > -1)
  1243. return eventBus.emit(CMD.SHOW_MSG, {
  1244. type: "error",
  1245. text: "请不要在每一个回复中都包括外链,这看起来像是在 spamming"
  1246. });
  1247. let r2 = res.search("创建新回复");
  1248. if (r2 > -1) {
  1249. eventBus.emit(CMD.REFRESH_ONCE, res);
  1250. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
  1251. let clientWidth = window.win().document.body.clientWidth;
  1252. let windowWidth = 1200;
  1253. let left = clientWidth / 2 - windowWidth / 2;
  1254. let newWin = window.win().open("about:blank", "hello", `width=${windowWidth},height=600,left=${left},top=100`);
  1255. newWin.document.write(res);
  1256. return;
  1257. }
  1258. content.value = replyInfo;
  1259. emits("close");
  1260. eventBus.emit(CMD.REFRESH_ONCE, res);
  1261. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "回复成功" });
  1262. eventBus.emit(CMD.ADD_REPLY, item);
  1263. },
  1264. (err) => {
  1265. console.log("err", err);
  1266. loading.value = false;
  1267. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "回复失败" });
  1268. }
  1269. ).catch((r) => {
  1270. console.log("cathc", r);
  1271. });
  1272. }
  1273. function showEmoticons(e) {
  1274. if (isShowEmoticons.value) {
  1275. return isShowEmoticons.value = false;
  1276. }
  1277. let rect = e.currentTarget.getBoundingClientRect();
  1278. emoticonsRef.value.style.left = rect.left + 30 + "px";
  1279. emoticonsRef.value.style.bottom = window.innerHeight - rect.top - 20 + "px";
  1280. isShowEmoticons.value = true;
  1281. }
  1282. function off() {
  1283. eventBus.emit(CMD.SHOW_CALL, { show: false });
  1284. eventBus.off(CMD.SET_CALL);
  1285. }
  1286. function checkHeight() {
  1287. txtRef.value.style.height = 0;
  1288. txtRef.value.style.height = txtRef.value.scrollHeight + "px";
  1289. }
  1290. function insert(str) {
  1291. let cursorPos = txtRef.value.selectionStart;
  1292. let start = content.value.slice(0, cursorPos);
  1293. let end = content.value.slice(cursorPos, content.value.length);
  1294. content.value = start + str + end;
  1295. let moveCursorPos = start.length + str.length;
  1296. setTimeout(() => {
  1297. txtRef.value.focus();
  1298. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  1299. checkHeight();
  1300. });
  1301. }
  1302. function showCallPopover(text) {
  1303. let r = cursorRef.value.getBoundingClientRect();
  1304. eventBus.emit(CMD.SHOW_CALL, { show: true, top: r.top, left: r.left, text });
  1305. eventBus.off(CMD.SET_CALL);
  1306. eventBus.on(CMD.SET_CALL, (e) => {
  1307. let cursorPos = txtRef.value.selectionStart;
  1308. let start = content.value.slice(0, cursorPos);
  1309. let end = content.value.slice(cursorPos, content.value.length);
  1310. let lastCallPos = start.lastIndexOf("@");
  1311. start = content.value.slice(0, lastCallPos + 1);
  1312. if (e === "管理员") {
  1313. e = "Livid @Kai @Olivia @GordianZ @sparanoid";
  1314. }
  1315. if (e === "所有人") {
  1316. e = allReplyUsers.value.map((v, i) => {
  1317. if (i)
  1318. return "@" + v;
  1319. else
  1320. return v;
  1321. }).join(" ");
  1322. }
  1323. content.value = start + e + " " + end;
  1324. let moveCursorPos = start.length + e.length + 1;
  1325. setTimeout(() => {
  1326. txtRef.value.setSelectionRange(moveCursorPos, moveCursorPos);
  1327. checkHeight();
  1328. });
  1329. eventBus.off(CMD.SET_CALL);
  1330. });
  1331. }
  1332. function onKeydown(e) {
  1333. let code = e.keyCode;
  1334. switch (code) {
  1335. case 8:
  1336. if (content.value === "@") {
  1337. off();
  1338. }
  1339. break;
  1340. case 37:
  1341. case 38:
  1342. case 39:
  1343. case 40:
  1344. setTimeout(() => onInput({ data: "" }), 100);
  1345. break;
  1346. case 27:
  1347. e.preventDefault();
  1348. e.stopPropagation();
  1349. e.stopImmediatePropagation();
  1350. return false;
  1351. }
  1352. }
  1353. function onInput(e) {
  1354. let cursorPos = txtRef.value.selectionStart;
  1355. if (!content.value)
  1356. return;
  1357. if (e.data === " ") {
  1358. return off();
  1359. }
  1360. if (e.data === "@") {
  1361. if (content.value.length !== 1) {
  1362. if (content.value[cursorPos - 2] === " " || content.value[cursorPos - 2] === "\n") {
  1363. return showCallPopover("");
  1364. }
  1365. } else {
  1366. return showCallPopover("");
  1367. }
  1368. off();
  1369. } else {
  1370. let judgeStr = content.value.slice(0, cursorPos);
  1371. let lastCallPos = judgeStr.lastIndexOf("@");
  1372. if (lastCallPos === -1) {
  1373. return off();
  1374. }
  1375. let callStr = judgeStr.slice(lastCallPos, cursorPos);
  1376. let hasSpace = callStr.includes(" ");
  1377. if (hasSpace) {
  1378. off();
  1379. } else {
  1380. if (lastCallPos === 0) {
  1381. return showCallPopover(callStr.replace("@", ""));
  1382. }
  1383. if (content.value.length !== 1) {
  1384. if (content.value[lastCallPos - 1] === " " || content.value[lastCallPos - 1] === "\n") {
  1385. return showCallPopover(callStr.replace("@", ""));
  1386. }
  1387. } else {
  1388. return showCallPopover(callStr.replace("@", ""));
  1389. }
  1390. off();
  1391. }
  1392. }
  1393. }
  1394. function onBlur() {
  1395. isFocus.value = false;
  1396. }
  1397. vue.onMounted(() => {
  1398. $(`.${editorId.value}`).each(function() {
  1399. this.setAttribute("style", "height:" + this.scrollHeight + "px;overflow-y:hidden;");
  1400. }).on("input", function() {
  1401. this.style.height = 0;
  1402. this.style.height = this.scrollHeight + "px";
  1403. });
  1404. if (useType === "reply-comment") {
  1405. txtRef.value && txtRef.value.focus();
  1406. }
  1407. });
  1408. vue.onBeforeUnmount(() => {
  1409. $(`.${editorId.value}`).off();
  1410. });
  1411. return (_ctx, _cache) => {
  1412. return vue.openBlock(), vue.createElementBlock("div", {
  1413. class: vue.normalizeClass(["post-editor-wrapper", vue.unref(editorClass)])
  1414. }, [
  1415. vue.withDirectives(vue.createElementVNode("textarea", {
  1416. class: vue.normalizeClass(["post-editor", editorId.value]),
  1417. ref_key: "txtRef",
  1418. ref: txtRef,
  1419. onFocus: _cache[0] || (_cache[0] = ($event) => vue.isRef(isFocus) ? isFocus.value = true : isFocus = true),
  1420. onBlur,
  1421. placeholder: "请尽量让自己的回复能够对别人有帮助",
  1422. onInput,
  1423. onKeydown,
  1424. onDrop: drop,
  1425. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => content.value = $event)
  1426. }, null, 34), [
  1427. [vue.vModelText, content.value]
  1428. ]),
  1429. vue.createElementVNode("div", _hoisted_1$b, [
  1430. vue.createElementVNode("span", { innerHTML: vue.unref(cursorHtml) }, null, 8, _hoisted_2$9),
  1431. vue.createElementVNode("span", {
  1432. class: "cursor",
  1433. ref_key: "cursorRef",
  1434. ref: cursorRef
  1435. }, "|", 512)
  1436. ]),
  1437. vue.createElementVNode("div", _hoisted_3$6, [
  1438. vue.createElementVNode("div", _hoisted_4$5, [
  1439. (vue.openBlock(), vue.createElementBlock("svg", {
  1440. onClick: showEmoticons,
  1441. width: "20",
  1442. height: "20",
  1443. viewBox: "0 0 48 48",
  1444. fill: "none",
  1445. xmlns: "http://www.w3.org/2000/svg"
  1446. }, _hoisted_9$4)),
  1447. vue.createElementVNode("div", _hoisted_10$4, [
  1448. vue.createElementVNode("input", {
  1449. type: "file",
  1450. accept: "image/*",
  1451. onChange: _cache[2] || (_cache[2] = (e) => upload(e.currentTarget.files[0]))
  1452. }, null, 32),
  1453. _hoisted_11$4
  1454. ]),
  1455. uploadLoading.value ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_12$4, "上传中...")) : vue.createCommentVNode("", true)
  1456. ]),
  1457. vue.createElementVNode("div", {
  1458. class: vue.normalizeClass(["button", { disabled: vue.unref(disabled), loading: loading.value }]),
  1459. onClick: submit
  1460. }, "回复 ", 2)
  1461. ]),
  1462. vue.withDirectives(vue.createElementVNode("div", {
  1463. class: "emoticon-pack",
  1464. ref_key: "emoticonsRef",
  1465. ref: emoticonsRef
  1466. }, [
  1467. vue.createElementVNode("i", {
  1468. class: "fa fa-times",
  1469. "aria-hidden": "true",
  1470. onClick: _cache[3] || (_cache[3] = ($event) => isShowEmoticons.value = false)
  1471. }),
  1472. _hoisted_13$4,
  1473. vue.createElementVNode("div", _hoisted_14$4, [
  1474. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(classicsEmoticons, (item) => {
  1475. return vue.createElementVNode("img", {
  1476. src: item.high,
  1477. onClick: ($event) => {
  1478. insert(item.name);
  1479. isShowEmoticons.value = false;
  1480. }
  1481. }, null, 8, _hoisted_15$4);
  1482. }), 64))
  1483. ]),
  1484. vue.createElementVNode("div", _hoisted_16$2, [
  1485. (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(emojiEmoticons, (item) => {
  1486. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  1487. vue.createElementVNode("div", _hoisted_17$2, vue.toDisplayString(item.title), 1),
  1488. vue.createElementVNode("div", _hoisted_18$2, [
  1489. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.list, (emoji) => {
  1490. return vue.openBlock(), vue.createElementBlock("span", {
  1491. onClick: ($event) => {
  1492. insert(emoji);
  1493. isShowEmoticons.value = false;
  1494. }
  1495. }, vue.toDisplayString(emoji), 9, _hoisted_19$2);
  1496. }), 256))
  1497. ])
  1498. ], 64);
  1499. }), 64))
  1500. ])
  1501. ], 512), [
  1502. [vue.vShow, isShowEmoticons.value]
  1503. ])
  1504. ], 2);
  1505. };
  1506. }
  1507. };
  1508. const PostEditor = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-48f028d5"]]);
  1509. const _hoisted_1$a = {
  1510. key: 0,
  1511. class: "html-wrapper"
  1512. };
  1513. const _hoisted_2$8 = ["innerHTML"];
  1514. const _sfc_main$a = {
  1515. __name: "BaseHtmlRender",
  1516. props: ["html"],
  1517. setup(__props) {
  1518. const props = __props;
  1519. const config2 = vue.inject("config");
  1520. const contentRef = vue.ref(null);
  1521. const checkHeight = 900;
  1522. const mask = vue.ref(false);
  1523. const handOpen = vue.ref(false);
  1524. function mouseup(e) {
  1525. if (!config2.value.base64)
  1526. return;
  1527. let selectionText = window.win().getSelection().toString();
  1528. if (selectionText) {
  1529. let r = selectionText.match(/([A-Za-z0-9+/=]+)/g);
  1530. if (r) {
  1531. if (r[0].length < 4)
  1532. return;
  1533. eventBus.emit(CMD.SHOW_TOOLTIP, { text: r[0], e });
  1534. }
  1535. }
  1536. }
  1537. vue.watch(config2.value, (newVale) => {
  1538. if (!newVale.contentAutoCollapse) {
  1539. mask.value = false;
  1540. }
  1541. });
  1542. vue.watch([() => contentRef.value, () => props.html], () => {
  1543. if (!contentRef.value || !props.html)
  1544. return;
  1545. if (!config2.value.contentAutoCollapse)
  1546. return;
  1547. contentRef.value.querySelectorAll("img").forEach((item) => {
  1548. item.removeEventListener("load", checkContentHeight);
  1549. item.addEventListener("load", checkContentHeight);
  1550. });
  1551. checkContentHeight();
  1552. }, { immediate: true, flush: "post" });
  1553. function checkContentHeight() {
  1554. if (handOpen.value)
  1555. return;
  1556. let rect = contentRef.value.getBoundingClientRect();
  1557. mask.value = rect.height >= checkHeight;
  1558. }
  1559. return (_ctx, _cache) => {
  1560. return props.html ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$a, [
  1561. vue.createElementVNode("div", {
  1562. class: vue.normalizeClass({ mask: mask.value })
  1563. }, [
  1564. vue.createElementVNode("div", vue.mergeProps({
  1565. ref_key: "contentRef",
  1566. ref: contentRef
  1567. }, _ctx.$attrs, {
  1568. innerHTML: props.html,
  1569. onMouseup: mouseup
  1570. }), null, 16, _hoisted_2$8)
  1571. ], 2),
  1572. mask.value ? (vue.openBlock(), vue.createElementBlock("div", {
  1573. key: 0,
  1574. class: "expand",
  1575. onClick: _cache[0] || (_cache[0] = ($event) => {
  1576. mask.value = false;
  1577. handOpen.value = true;
  1578. })
  1579. }, "展开")) : vue.createCommentVNode("", true)
  1580. ])) : vue.createCommentVNode("", true);
  1581. };
  1582. }
  1583. };
  1584. const BaseHtmlRender = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-a77c3d96"]]);
  1585. const _sfc_main$9 = {
  1586. name: "Comment",
  1587. components: { BaseHtmlRender, Author, PostEditor, Point },
  1588. inject: ["post", "postDetailWidth", "show", "isNight"],
  1589. props: {
  1590. modelValue: {
  1591. reply_content: ""
  1592. },
  1593. type: {
  1594. type: String,
  1595. default() {
  1596. return "list";
  1597. }
  1598. }
  1599. },
  1600. data() {
  1601. return {
  1602. edit: false,
  1603. ding: false,
  1604. expand: true,
  1605. expandWrong: false,
  1606. replyInfo: `@${this.modelValue.username} #${this.modelValue.floor} `,
  1607. cssStyle: null,
  1608. floor: this.modelValue.floor
  1609. };
  1610. },
  1611. watch: {
  1612. show(e) {
  1613. if (e) {
  1614. this.edit = false;
  1615. }
  1616. },
  1617. postDetailWidth(n, o) {
  1618. this.checkIsTooLong(n);
  1619. }
  1620. },
  1621. computed: {
  1622. myClass() {
  1623. return {
  1624. isOp: this.modelValue.isOp,
  1625. ding: this.ding,
  1626. isLevelOne: this.modelValue.level === 0,
  1627. ["c_" + this.floor]: this.type !== "top"
  1628. };
  1629. }
  1630. },
  1631. mounted() {
  1632. this.checkIsTooLong(this.postDetailWidth);
  1633. },
  1634. methods: {
  1635. checkIsTooLong(postDetailWidth) {
  1636. if (postDetailWidth !== 0) {
  1637. let rect = this.$refs.comment.getBoundingClientRect();
  1638. let ban = postDetailWidth / 2;
  1639. console.log("ban", ban);
  1640. if (ban < rect.width && rect.width < ban + 25 && this.modelValue.children.length) {
  1641. this.expand = false;
  1642. let padding = 2;
  1643. this.cssStyle = {
  1644. padding: "1rem 0",
  1645. width: `calc(${postDetailWidth}px - ${padding}rem)`,
  1646. transform: `translateX(calc(${rect.width - postDetailWidth}px + ${padding}rem))`,
  1647. background: this.isNight ? "#18222d" : "white"
  1648. };
  1649. }
  1650. }
  1651. },
  1652. //高亮一下
  1653. showDing() {
  1654. this.ding = true;
  1655. setTimeout(() => {
  1656. this.ding = false;
  1657. }, 2e3);
  1658. },
  1659. hide() {
  1660. let url = `${window.baseUrl}/ignore/reply/${this.modelValue.id}?once=${this.post.once}`;
  1661. eventBus.emit(CMD.REMOVE, this.modelValue.floor);
  1662. $.post(url).then((res) => {
  1663. eventBus.emit(CMD.REFRESH_ONCE);
  1664. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "隐藏成功" });
  1665. }, (err) => {
  1666. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "隐藏成功,仅本次有效(接口调用失败!)" });
  1667. });
  1668. },
  1669. toggle() {
  1670. this.expand = !this.expand;
  1671. }
  1672. }
  1673. };
  1674. const _withScopeId$5 = (n) => (vue.pushScopeId("data-v-a0031aa2"), n = n(), vue.popScopeId(), n);
  1675. const _hoisted_1$9 = ["data-floor"];
  1676. const _hoisted_2$7 = { class: "comment-content" };
  1677. const _hoisted_3$5 = { class: "right" };
  1678. const _hoisted_4$4 = { class: "w" };
  1679. const _hoisted_5$4 = {
  1680. key: 0,
  1681. class: "wrong-wrapper"
  1682. };
  1683. const _hoisted_6$4 = ["href"];
  1684. const _hoisted_7$3 = { class: "del-line" };
  1685. const _hoisted_8$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("i", {
  1686. class: "fa fa-question-circle-o wrong-icon",
  1687. "aria-hidden": "true"
  1688. }, null, -1));
  1689. const _hoisted_9$3 = {
  1690. key: 0,
  1691. class: "warning"
  1692. };
  1693. const _hoisted_10$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  1694. const _hoisted_11$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  1695. const _hoisted_12$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  1696. const _hoisted_13$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  1697. const _hoisted_14$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
  1698. const _hoisted_15$3 = /* @__PURE__ */ _withScopeId$5(() => /* @__PURE__ */ vue.createElementVNode("a", {
  1699. href: "https://github.com/zyronon/v2ex-script/discussions/7",
  1700. target: "_blank"
  1701. }, "这里", -1));
  1702. function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
  1703. const _component_Author = vue.resolveComponent("Author");
  1704. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  1705. const _component_PostEditor = vue.resolveComponent("PostEditor");
  1706. const _component_Comment = vue.resolveComponent("Comment", true);
  1707. return vue.openBlock(), vue.createElementBlock("div", {
  1708. class: vue.normalizeClass(["comment", $options.myClass]),
  1709. ref: "comment",
  1710. "data-floor": $data.floor
  1711. }, [
  1712. vue.createVNode(_component_Author, {
  1713. modelValue: $data.expand,
  1714. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.expand = $event),
  1715. comment: $props.modelValue,
  1716. onReply: _cache[1] || (_cache[1] = ($event) => $data.edit = !$data.edit),
  1717. type: $props.type,
  1718. onHide: $options.hide
  1719. }, null, 8, ["modelValue", "comment", "type", "onHide"]),
  1720. $data.cssStyle && !$data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  1721. key: 0,
  1722. class: "more ago",
  1723. onClick: _cache[2] || (_cache[2] = ($event) => $data.expand = !$data.expand)
  1724. }, " 由于嵌套回复层级太深,自动将后续回复隐藏 ")) : vue.createCommentVNode("", true),
  1725. $data.expand ? (vue.openBlock(), vue.createElementBlock("div", {
  1726. key: 1,
  1727. class: "comment-content-w",
  1728. style: vue.normalizeStyle($data.cssStyle)
  1729. }, [
  1730. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  1731. key: 0,
  1732. class: "more ago",
  1733. onClick: _cache[3] || (_cache[3] = ($event) => $data.expand = !$data.expand)
  1734. }, " 由于嵌套回复层级太深,自动将以下回复移至可见范围 ")) : vue.createCommentVNode("", true),
  1735. vue.createElementVNode("div", _hoisted_2$7, [
  1736. vue.createElementVNode("div", {
  1737. class: "left expand-line",
  1738. onClick: _cache[4] || (_cache[4] = (...args) => $options.toggle && $options.toggle(...args))
  1739. }),
  1740. vue.createElementVNode("div", _hoisted_3$5, [
  1741. vue.createElementVNode("div", _hoisted_4$4, [
  1742. $props.modelValue.isWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$4, [
  1743. vue.createElementVNode("span", {
  1744. onClick: _cache[5] || (_cache[5] = ($event) => $data.expandWrong = !$data.expandWrong),
  1745. title: "点击楼层号查看提示"
  1746. }, [
  1747. vue.createElementVNode("a", {
  1748. href: "/member/" + $props.modelValue.replyUsers[0]
  1749. }, "@" + vue.toDisplayString($props.modelValue.replyUsers[0]) + "  ", 9, _hoisted_6$4),
  1750. vue.createElementVNode("span", _hoisted_7$3, "#" + vue.toDisplayString($props.modelValue.replyFloor), 1),
  1751. _hoisted_8$3
  1752. ]),
  1753. $data.expandWrong ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$3, [
  1754. vue.createTextVNode(" 这条回复似乎有点问题,指定的楼层号与@的人对应不上 "),
  1755. _hoisted_10$3,
  1756. vue.createTextVNode(" 原因可能有下面几种: "),
  1757. _hoisted_11$3,
  1758. vue.createTextVNode(" 一、屏蔽用户导致楼层塌陷:你屏蔽了A,自A以后的回复的楼层号都会减1 "),
  1759. _hoisted_12$3,
  1760. vue.createTextVNode(" 二、忽略回复导致楼层塌陷:原理同上 "),
  1761. _hoisted_13$3,
  1762. vue.createTextVNode(" 三、层主回复时指定错了楼层号(同一,层主屏蔽了别人,导致楼层塌陷) "),
  1763. _hoisted_14$3,
  1764. vue.createTextVNode(" 四、脚本解析错误,请在"),
  1765. _hoisted_15$3,
  1766. vue.createTextVNode("反馈 ")
  1767. ])) : vue.createCommentVNode("", true)
  1768. ])) : vue.createCommentVNode("", true),
  1769. vue.createVNode(_component_BaseHtmlRender, {
  1770. class: "reply_content",
  1771. html: $props.modelValue.reply_content
  1772. }, null, 8, ["html"]),
  1773. $data.edit ? (vue.openBlock(), vue.createBlock(_component_PostEditor, {
  1774. key: 1,
  1775. onClose: _cache[6] || (_cache[6] = ($event) => $data.edit = false),
  1776. replyInfo: $data.replyInfo,
  1777. replyUser: $props.modelValue.username,
  1778. replyFloor: $props.modelValue.floor
  1779. }, null, 8, ["replyInfo", "replyUser", "replyFloor"])) : vue.createCommentVNode("", true)
  1780. ]),
  1781. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($props.modelValue.children, (item, index2) => {
  1782. return vue.openBlock(), vue.createBlock(_component_Comment, {
  1783. modelValue: $props.modelValue.children[index2],
  1784. "onUpdate:modelValue": ($event) => $props.modelValue.children[index2] = $event,
  1785. key: index2
  1786. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  1787. }), 128))
  1788. ])
  1789. ]),
  1790. $data.cssStyle ? (vue.openBlock(), vue.createElementBlock("div", {
  1791. key: 1,
  1792. class: "more ago",
  1793. onClick: _cache[7] || (_cache[7] = ($event) => $data.expand = !$data.expand)
  1794. }, " 由于嵌套回复层级太深,自动将以上回复移至可见范围 ")) : vue.createCommentVNode("", true)
  1795. ], 4)) : vue.createCommentVNode("", true)
  1796. ], 10, _hoisted_1$9);
  1797. }
  1798. const Comment = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$5], ["__scopeId", "data-v-a0031aa2"]]);
  1799. const _sfc_main$8 = {
  1800. name: "Toolbar",
  1801. inject: [
  1802. "isLogin",
  1803. "post",
  1804. "pageType"
  1805. ],
  1806. data() {
  1807. return {
  1808. timer: null,
  1809. loading: false,
  1810. loading2: false,
  1811. loading3: false
  1812. };
  1813. },
  1814. methods: {
  1815. checkIsLogin(emitName = "") {
  1816. if (!this.isLogin) {
  1817. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "请先登录(不可用)!" });
  1818. return false;
  1819. }
  1820. this.$emit(emitName);
  1821. return true;
  1822. },
  1823. getColor(val) {
  1824. return val ? "#ff4500" : "#929596";
  1825. },
  1826. getIsFull(val) {
  1827. return val ? "#ff4500" : "none";
  1828. },
  1829. tweet() {
  1830. if (!this.checkIsLogin())
  1831. return;
  1832. let username = window.user.username;
  1833. let url = `https://twitter.com/intent/tweet?url=${window.baseUrl}/t/${this.post.id}?r=${username}&related=v2ex&text=${this.post.title}`;
  1834. window.win().open(url, "_blank", "width=550,height=370");
  1835. },
  1836. report() {
  1837. if (!this.checkIsLogin())
  1838. return;
  1839. if (!this.isLogin)
  1840. return;
  1841. if (this.post.isReport)
  1842. return;
  1843. let username = window.user.username;
  1844. let url = `https://twitter.com/share?url=${window.baseUrl}/t/${this.post.id}?r=${username}&amp;related=v2ex&amp;hashtags=apple&amp;text=${this.post.title}`;
  1845. window.win().open(url, "_blank", "width=550,height=370");
  1846. },
  1847. async toggleIgnore() {
  1848. if (!this.checkIsLogin())
  1849. return;
  1850. let url = `${window.baseUrl}/${this.post.isIgnore ? "unignore" : "ignore"}/topic/${this.post.id}?once=${this.post.once}`;
  1851. if (this.pageType === "post") {
  1852. this.loading2 = true;
  1853. let apiRes = await window.win().fetch(url);
  1854. if (apiRes.redirected) {
  1855. if (!this.post.isIgnore) {
  1856. window.win().location = window.baseUrl;
  1857. }
  1858. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  1859. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  1860. } else {
  1861. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略失败" });
  1862. }
  1863. this.loading2 = false;
  1864. } else {
  1865. if (this.post.isIgnore) {
  1866. this.loading2 = true;
  1867. } else {
  1868. eventBus.emit(CMD.IGNORE);
  1869. }
  1870. let apiRes = await window.win().fetch(url);
  1871. if (apiRes.redirected) {
  1872. if (this.post.isIgnore) {
  1873. eventBus.emit(CMD.REFRESH_ONCE);
  1874. }
  1875. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isIgnore ? "取消成功" : "忽略成功" });
  1876. eventBus.emit(CMD.MERGE, { isIgnore: !this.post.isIgnore });
  1877. } else {
  1878. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "忽略成功,仅本次有效(接口调用失败!)" });
  1879. }
  1880. this.loading2 = false;
  1881. }
  1882. },
  1883. async toggleFavorite() {
  1884. if (!this.post.isFavorite && config.collectBrowserNotice) {
  1885. alert("请按Command/Cmd/CTRL + D添加到书签");
  1886. }
  1887. if (!this.checkIsLogin())
  1888. return;
  1889. this.loading = true;
  1890. let url = `${window.baseUrl}/${this.post.isFavorite ? "unfavorite" : "favorite"}/topic/${this.post.id}?once=${this.post.once}`;
  1891. let apiRes = await window.win().fetch(url);
  1892. this.loading = false;
  1893. if (apiRes.redirected) {
  1894. let htmlText = await apiRes.text();
  1895. if (htmlText.search(this.post.isFavorite ? "加入收藏" : "取消收藏")) {
  1896. eventBus.emit(CMD.MERGE, { collectCount: this.post.isFavorite ? this.post.collectCount - 1 : this.post.collectCount + 1 });
  1897. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: this.post.isFavorite ? "取消成功" : "收藏成功" });
  1898. eventBus.emit(CMD.REFRESH_ONCE, htmlText);
  1899. eventBus.emit(CMD.MERGE, { isFavorite: !this.post.isFavorite });
  1900. return;
  1901. }
  1902. }
  1903. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "操作失败" });
  1904. }
  1905. }
  1906. };
  1907. const _withScopeId$4 = (n) => (vue.pushScopeId("data-v-07fa3ae8"), n = n(), vue.popScopeId(), n);
  1908. const _hoisted_1$8 = { class: "toolbar" };
  1909. const _hoisted_2$6 = /* @__PURE__ */ vue.createStaticVNode('<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-07fa3ae8><path d="M4 6H44V36H29L24 41L19 36H4V6Z" fill="none" stroke="#929596" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-07fa3ae8></path><path d="M23 21H25.0025" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-07fa3ae8></path><path d="M33.001 21H34.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-07fa3ae8></path><path d="M13.001 21H14.9999" stroke="#929596" stroke-width="2" stroke-linecap="round" data-v-07fa3ae8></path></svg><span data-v-07fa3ae8>回复</span>', 2);
  1910. const _hoisted_4$3 = [
  1911. _hoisted_2$6
  1912. ];
  1913. const _hoisted_5$3 = {
  1914. viewBox: "0 0 48 48",
  1915. fill: "none",
  1916. xmlns: "http://www.w3.org/2000/svg"
  1917. };
  1918. const _hoisted_6$3 = ["fill", "stroke"];
  1919. const _hoisted_7$2 = {
  1920. key: 1,
  1921. class: "tool no-hover"
  1922. };
  1923. const _hoisted_8$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  1924. viewBox: "0 0 48 48",
  1925. fill: "none",
  1926. xmlns: "http://www.w3.org/2000/svg"
  1927. }, [
  1928. /* @__PURE__ */ vue.createElementVNode("path", {
  1929. d: "M28 6H42V20",
  1930. stroke: "#929596",
  1931. "stroke-width": "2",
  1932. "stroke-linecap": "round",
  1933. "stroke-linejoin": "round"
  1934. }),
  1935. /* @__PURE__ */ vue.createElementVNode("path", {
  1936. d: "M42 29.4737V39C42 40.6569 40.6569 42 39 42H9C7.34315 42 6 40.6569 6 39V9C6 7.34315 7.34315 6 9 6L18 6",
  1937. stroke: "#929596",
  1938. "stroke-width": "2",
  1939. "stroke-linecap": "round",
  1940. "stroke-linejoin": "round"
  1941. }),
  1942. /* @__PURE__ */ vue.createElementVNode("path", {
  1943. d: "M25.7998 22.1999L41.0998 6.8999",
  1944. stroke: "#929596",
  1945. "stroke-width": "2",
  1946. "stroke-linecap": "round",
  1947. "stroke-linejoin": "round"
  1948. })
  1949. ], -1));
  1950. const _hoisted_9$2 = /* @__PURE__ */ _withScopeId$4(() => /* @__PURE__ */ vue.createElementVNode("span", null, "Tweet", -1));
  1951. const _hoisted_10$2 = [
  1952. _hoisted_8$2,
  1953. _hoisted_9$2
  1954. ];
  1955. const _hoisted_11$2 = {
  1956. viewBox: "0 0 48 48",
  1957. fill: "none",
  1958. xmlns: "http://www.w3.org/2000/svg"
  1959. };
  1960. const _hoisted_12$2 = ["fill", "stroke"];
  1961. const _hoisted_13$2 = ["fill", "stroke"];
  1962. const _hoisted_14$2 = ["fill", "stroke"];
  1963. const _hoisted_15$2 = /* @__PURE__ */ vue.createStaticVNode('<svg width="19" height="19" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-07fa3ae8><path d="M36 35H12V21C12 14.3726 17.3726 9 24 9C30.6274 9 36 14.3726 36 21V35Z" fill="#929596" stroke="#929596" stroke-width="4" stroke-linejoin="round" data-v-07fa3ae8></path><path d="M8 42H40" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-07fa3ae8></path><path d="M4 13L7 14" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-07fa3ae8></path><path d="M13 3.9999L14 6.9999" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-07fa3ae8></path><path d="M10.0001 9.99989L7.00009 6.99989" stroke="#929596" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" data-v-07fa3ae8></path></svg>', 1);
  1964. function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) {
  1965. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$8, [
  1966. vue.createElementVNode("div", {
  1967. class: "tool",
  1968. onClick: _cache[0] || (_cache[0] = ($event) => $options.checkIsLogin("reply"))
  1969. }, _hoisted_4$3),
  1970. $options.post.once ? (vue.openBlock(), vue.createElementBlock("div", {
  1971. key: 0,
  1972. class: vue.normalizeClass(["tool", { loading: $data.loading }]),
  1973. onClick: _cache[1] || (_cache[1] = (...args) => $options.toggleFavorite && $options.toggleFavorite(...args))
  1974. }, [
  1975. (vue.openBlock(), vue.createElementBlock("svg", _hoisted_5$3, [
  1976. vue.createElementVNode("path", {
  1977. d: "M23.9986 5L17.8856 17.4776L4 19.4911L14.0589 29.3251L11.6544 43L23.9986 36.4192L36.3454 43L33.9586 29.3251L44 19.4911L30.1913 17.4776L23.9986 5Z",
  1978. fill: $options.getIsFull($options.post.isFavorite),
  1979. stroke: $options.getColor($options.post.isFavorite),
  1980. "stroke-width": "2",
  1981. "stroke-linejoin": "round"
  1982. }, null, 8, _hoisted_6$3)
  1983. ])),
  1984. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isFavorite ? "取消收藏" : "加入收藏"), 1)
  1985. ], 2)) : vue.createCommentVNode("", true),
  1986. $options.post.once && $options.post.collectCount !== 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7$2, [
  1987. vue.createElementVNode("span", null, vue.toDisplayString($options.post.collectCount + "人收藏"), 1)
  1988. ])) : vue.createCommentVNode("", true),
  1989. vue.createElementVNode("div", {
  1990. class: "tool",
  1991. onClick: _cache[2] || (_cache[2] = (...args) => $options.tweet && $options.tweet(...args))
  1992. }, _hoisted_10$2),
  1993. $options.post.once ? (vue.openBlock(), vue.createElementBlock("div", {
  1994. key: 2,
  1995. class: vue.normalizeClass(["tool", { "loading": $data.loading2 }]),
  1996. onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleIgnore && $options.toggleIgnore(...args))
  1997. }, [
  1998. (vue.openBlock(), vue.createElementBlock("svg", _hoisted_11$2, [
  1999. vue.createElementVNode("path", {
  2000. fill: $options.getIsFull($options.post.isIgnore),
  2001. stroke: $options.getColor($options.post.isIgnore),
  2002. d: "M9.85786 18C6.23858 21 4 24 4 24C4 24 12.9543 36 24 36C25.3699 36 26.7076 35.8154 28 35.4921M20.0318 12.5C21.3144 12.1816 22.6414 12 24 12C35.0457 12 44 24 44 24C44 24 41.7614 27 38.1421 30",
  2003. "stroke-width": "2",
  2004. "stroke-linecap": "round",
  2005. "stroke-linejoin": "round"
  2006. }, null, 8, _hoisted_12$2),
  2007. vue.createElementVNode("path", {
  2008. fill: $options.getIsFull($options.post.isIgnore),
  2009. d: "M20.3142 20.6211C19.4981 21.5109 19 22.6972 19 23.9998C19 26.7612 21.2386 28.9998 24 28.9998C25.3627 28.9998 26.5981 28.4546 27.5 27.5705",
  2010. stroke: $options.getColor($options.post.isIgnore),
  2011. "stroke-width": "2",
  2012. "stroke-linecap": "round",
  2013. "stroke-linejoin": "round"
  2014. }, null, 8, _hoisted_13$2),
  2015. vue.createElementVNode("path", {
  2016. d: "M42 42L6 6",
  2017. fill: $options.getIsFull($options.post.isIgnore),
  2018. stroke: $options.getColor($options.post.isIgnore),
  2019. "stroke-width": "2",
  2020. "stroke-linecap": "round",
  2021. "stroke-linejoin": "round"
  2022. }, null, 8, _hoisted_14$2)
  2023. ])),
  2024. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isIgnore ? "取消忽略" : "忽略主题"), 1)
  2025. ], 2)) : vue.createCommentVNode("", true),
  2026. $options.post.once && $options.post.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
  2027. key: 3,
  2028. class: vue.normalizeClass(["tool", { "loading": $data.loading3, "no-hover": $options.post.isLogin }]),
  2029. onClick: _cache[4] || (_cache[4] = (...args) => $options.report && $options.report(...args))
  2030. }, [
  2031. _hoisted_15$2,
  2032. vue.createElementVNode("span", null, vue.toDisplayString($options.post.isReport ? "你已对本主题进行了报告" : "报告这个主题"), 1)
  2033. ], 2)) : vue.createCommentVNode("", true)
  2034. ]);
  2035. }
  2036. const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$4], ["__scopeId", "data-v-07fa3ae8"]]);
  2037. const _sfc_main$7 = {
  2038. name: "Tooltip",
  2039. props: {
  2040. title: {
  2041. type: String,
  2042. default() {
  2043. return "";
  2044. }
  2045. }
  2046. },
  2047. data() {
  2048. return {
  2049. show: false
  2050. };
  2051. },
  2052. methods: {
  2053. hoverIn(e) {
  2054. let rect = e.target.getBoundingClientRect();
  2055. this.show = true;
  2056. vue.nextTick(() => {
  2057. let tip = this.$refs.tip.getBoundingClientRect();
  2058. this.$refs.tip.style.top = rect.top - tip.height - 5 + "px";
  2059. this.$refs.tip.style.left = rect.left + rect.width / 2 + "px";
  2060. });
  2061. }
  2062. }
  2063. };
  2064. const _hoisted_1$7 = { class: "pop-confirm" };
  2065. function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
  2066. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$7, [
  2067. (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
  2068. vue.createVNode(vue.Transition, null, {
  2069. default: vue.withCtx(() => [
  2070. $data.show ? (vue.openBlock(), vue.createElementBlock("div", {
  2071. key: 0,
  2072. class: "tip",
  2073. ref: "tip"
  2074. }, vue.toDisplayString($props.title), 513)) : vue.createCommentVNode("", true)
  2075. ]),
  2076. _: 1
  2077. })
  2078. ])),
  2079. vue.createElementVNode("span", {
  2080. onMouseenter: _cache[0] || (_cache[0] = (...args) => $options.hoverIn && $options.hoverIn(...args)),
  2081. onMouseleave: _cache[1] || (_cache[1] = ($event) => $data.show = false)
  2082. }, [
  2083. vue.renderSlot(_ctx.$slots, "default")
  2084. ], 32)
  2085. ]);
  2086. }
  2087. const Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$3]]);
  2088. const _withScopeId$3 = (n) => (vue.pushScopeId("data-v-3eb530b9"), n = n(), vue.popScopeId(), n);
  2089. const _hoisted_1$6 = {
  2090. class: "comment",
  2091. ref: "comment"
  2092. };
  2093. const _hoisted_2$5 = ["href"];
  2094. const _hoisted_3$4 = ["src"];
  2095. const _hoisted_4$2 = { class: "texts" };
  2096. const _hoisted_5$2 = {
  2097. key: 0,
  2098. class: "point"
  2099. };
  2100. const _hoisted_6$2 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2101. width: "19",
  2102. height: "19",
  2103. viewBox: "0 0 48 48",
  2104. fill: "none"
  2105. }, [
  2106. /* @__PURE__ */ vue.createElementVNode("path", {
  2107. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  2108. fill: "#E02A2A",
  2109. stroke: "#E02A2A",
  2110. "stroke-width": "2",
  2111. "stroke-linecap": "round",
  2112. "stroke-linejoin": "round"
  2113. })
  2114. ], -1));
  2115. const _hoisted_7$1 = { class: "num" };
  2116. const _hoisted_8$1 = { class: "my-tag" };
  2117. const _hoisted_9$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  2118. const _hoisted_10$1 = {
  2119. key: 2,
  2120. class: "ago"
  2121. };
  2122. const _hoisted_11$1 = {
  2123. key: 3,
  2124. class: "mod"
  2125. };
  2126. const _hoisted_12$1 = {
  2127. key: 4,
  2128. class: "op"
  2129. };
  2130. const _hoisted_13$1 = ["href"];
  2131. const _hoisted_14$1 = {
  2132. key: 5,
  2133. class: "op"
  2134. };
  2135. const _hoisted_15$1 = {
  2136. key: 6,
  2137. class: "mod"
  2138. };
  2139. const _hoisted_16$1 = {
  2140. key: 7,
  2141. class: "ago"
  2142. };
  2143. const _hoisted_17$1 = { class: "my-tag" };
  2144. const _hoisted_18$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-tag" }, null, -1));
  2145. const _hoisted_19$1 = {
  2146. key: 9,
  2147. class: "point"
  2148. };
  2149. const _hoisted_20$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2150. width: "19",
  2151. height: "19",
  2152. viewBox: "0 0 48 48",
  2153. fill: "none"
  2154. }, [
  2155. /* @__PURE__ */ vue.createElementVNode("path", {
  2156. d: "M15 8C8.92487 8 4 12.9249 4 19C4 30 17 40 24 42.3262C31 40 44 30 44 19C44 12.9249 39.0751 8 33 8C29.2797 8 25.9907 9.8469 24 12.6738C22.0093 9.8469 18.7203 8 15 8Z",
  2157. fill: "#E02A2A",
  2158. stroke: "#E02A2A",
  2159. "stroke-width": "2",
  2160. "stroke-linecap": "round",
  2161. "stroke-linejoin": "round"
  2162. })
  2163. ], -1));
  2164. const _hoisted_21$1 = { class: "num" };
  2165. const _hoisted_22$1 = ["href"];
  2166. const _hoisted_23$1 = ["src"];
  2167. const _hoisted_24$1 = { class: "Author-right" };
  2168. const _hoisted_25$1 = { class: "floor" };
  2169. const _hoisted_26$1 = /* @__PURE__ */ _withScopeId$3(() => /* @__PURE__ */ vue.createElementVNode("span", null, "跳转", -1));
  2170. const _hoisted_27$1 = [
  2171. _hoisted_26$1
  2172. ];
  2173. const _sfc_main$6 = {
  2174. __name: "SingleComment",
  2175. props: {
  2176. comment: {
  2177. reply_content: ""
  2178. },
  2179. isRight: {
  2180. type: Boolean,
  2181. default() {
  2182. return false;
  2183. }
  2184. }
  2185. },
  2186. setup(__props) {
  2187. const props = __props;
  2188. const config2 = vue.inject("config");
  2189. const isLogin = vue.inject("isLogin");
  2190. const tags = vue.inject("tags");
  2191. const myTags = vue.computed(() => {
  2192. return tags[props.comment.username] ?? [];
  2193. });
  2194. function jump() {
  2195. eventBus.emit(CMD.JUMP, props.comment.floor);
  2196. }
  2197. return (_ctx, _cache) => {
  2198. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$6, [
  2199. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  2200. key: 0,
  2201. class: "avatar",
  2202. href: `/member/${__props.comment.username}`
  2203. }, [
  2204. vue.createElementVNode("img", {
  2205. src: __props.comment.avatar,
  2206. alt: ""
  2207. }, null, 8, _hoisted_3$4)
  2208. ], 8, _hoisted_2$5)) : vue.createCommentVNode("", true),
  2209. vue.createElementVNode("div", {
  2210. class: vue.normalizeClass(["comment-body", { isRight: __props.isRight }])
  2211. }, [
  2212. vue.createElementVNode("div", _hoisted_4$2, [
  2213. __props.comment.thankCount && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$2, [
  2214. _hoisted_6$2,
  2215. vue.createElementVNode("div", _hoisted_7$1, vue.toDisplayString(__props.comment.thankCount), 1)
  2216. ])) : vue.createCommentVNode("", true),
  2217. vue.unref(isLogin) && vue.unref(config2).openTag && __props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(vue.unref(myTags), (i) => {
  2218. return vue.openBlock(), vue.createElementBlock("span", _hoisted_8$1, [
  2219. _hoisted_9$1,
  2220. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  2221. ]);
  2222. }), 256)) : vue.createCommentVNode("", true),
  2223. __props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_10$1, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  2224. __props.comment.isMod && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$1, "MOD")) : vue.createCommentVNode("", true),
  2225. __props.comment.isOp && __props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$1, "OP")) : vue.createCommentVNode("", true),
  2226. vue.createElementVNode("a", {
  2227. href: `/member/${__props.comment.username}`,
  2228. class: "username"
  2229. }, vue.toDisplayString(__props.comment.username), 9, _hoisted_13$1),
  2230. __props.comment.isOp && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$1, "OP")) : vue.createCommentVNode("", true),
  2231. __props.comment.isMod && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_15$1, "MOD")) : vue.createCommentVNode("", true),
  2232. !__props.isRight ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_16$1, vue.toDisplayString(__props.comment.date), 1)) : vue.createCommentVNode("", true),
  2233. vue.unref(isLogin) && vue.unref(config2).openTag && !__props.isRight ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 8 }, vue.renderList(vue.unref(myTags), (i) => {
  2234. return vue.openBlock(), vue.createElementBlock("span", _hoisted_17$1, [
  2235. _hoisted_18$1,
  2236. vue.createElementVNode("span", null, vue.toDisplayString(i), 1)
  2237. ]);
  2238. }), 256)) : vue.createCommentVNode("", true),
  2239. __props.comment.thankCount && !__props.isRight ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_19$1, [
  2240. _hoisted_20$1,
  2241. vue.createElementVNode("div", _hoisted_21$1, vue.toDisplayString(__props.comment.thankCount), 1)
  2242. ])) : vue.createCommentVNode("", true)
  2243. ]),
  2244. vue.createVNode(vue.unref(BaseHtmlRender), {
  2245. class: "reply_content",
  2246. html: __props.comment.reply_content
  2247. }, null, 8, ["html"])
  2248. ], 2),
  2249. __props.isRight ? (vue.openBlock(), vue.createElementBlock("a", {
  2250. key: 1,
  2251. class: "avatar",
  2252. href: `/member/${__props.comment.username}`
  2253. }, [
  2254. vue.createElementVNode("img", {
  2255. src: __props.comment.avatar,
  2256. alt: ""
  2257. }, null, 8, _hoisted_23$1)
  2258. ], 8, _hoisted_22$1)) : vue.createCommentVNode("", true),
  2259. vue.createElementVNode("div", _hoisted_24$1, [
  2260. vue.createElementVNode("div", _hoisted_25$1, vue.toDisplayString(__props.comment.floor), 1),
  2261. vue.createElementVNode("div", {
  2262. class: "tool jump",
  2263. onClick: jump
  2264. }, _hoisted_27$1)
  2265. ])
  2266. ], 512);
  2267. };
  2268. }
  2269. };
  2270. const SingleComment = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-3eb530b9"]]);
  2271. function debounce(fn, delay, scope) {
  2272. let timer = null;
  2273. return function() {
  2274. let context = scope || this, args = arguments;
  2275. clearTimeout(timer);
  2276. timer = setTimeout(function() {
  2277. fn.apply(context, args);
  2278. timer = null;
  2279. }, delay);
  2280. };
  2281. }
  2282. const _sfc_main$5 = {
  2283. name: "detail",
  2284. components: {
  2285. SingleComment,
  2286. PopConfirm,
  2287. Comment,
  2288. PostEditor,
  2289. Point,
  2290. Toolbar,
  2291. BaseHtmlRender,
  2292. Tooltip
  2293. },
  2294. inject: ["allReplyUsers", "post", "isLogin", "config", "pageType", "isNight", "showConfig"],
  2295. provide() {
  2296. return {
  2297. postDetailWidth: vue.computed(() => this.postDetailWidth)
  2298. };
  2299. },
  2300. props: {
  2301. modelValue: {
  2302. type: Boolean,
  2303. default() {
  2304. return false;
  2305. }
  2306. },
  2307. loading: {
  2308. type: Boolean,
  2309. default() {
  2310. return false;
  2311. }
  2312. },
  2313. displayType: 0
  2314. },
  2315. data() {
  2316. return {
  2317. isSticky: false,
  2318. selectCallIndex: 0,
  2319. postDetailWidth: 0,
  2320. showCallList: false,
  2321. showRelationReply: false,
  2322. replyText: "",
  2323. callStyle: {
  2324. top: 0,
  2325. left: 0
  2326. },
  2327. targetUser: {
  2328. left: [],
  2329. right: "",
  2330. rightFloor: -1
  2331. },
  2332. debounceScroll: () => {
  2333. },
  2334. read: {
  2335. floor: 0,
  2336. total: 0
  2337. },
  2338. currentFloor: 1
  2339. };
  2340. },
  2341. computed: {
  2342. isPost() {
  2343. return this.pageType === PageType.Post;
  2344. },
  2345. filterCallList() {
  2346. if (this.showCallList) {
  2347. let list = ["管理员", "所有人"].concat(this.allReplyUsers);
  2348. if (this.replyText)
  2349. return list.filter((i) => i.search(this.replyText) > -1);
  2350. return list;
  2351. }
  2352. return [];
  2353. },
  2354. topReply() {
  2355. return this.post.replyList.filter((v) => v.thankCount >= this.config.topReplyLoveMinCount).sort((a, b) => b.thankCount - a.thankCount).slice(0, this.config.topReplyCount);
  2356. },
  2357. replyList() {
  2358. if (this.displayType === 0)
  2359. return this.post.nestedReplies;
  2360. if (this.displayType === 1) {
  2361. return window.clone(this.post.nestedReplies).sort((a, b) => b.thankCount - a.thankCount);
  2362. }
  2363. if (this.displayType === 2)
  2364. return this.post.replyList;
  2365. if (this.displayType === 3)
  2366. return this.post.replyList.filter((v) => {
  2367. var _a;
  2368. return v.username === ((_a = this.post.member) == null ? void 0 : _a.username);
  2369. });
  2370. return [];
  2371. },
  2372. //关联回复
  2373. relationReply() {
  2374. if (this.targetUser.left.length && this.targetUser.right) {
  2375. return this.post.replyList.filter((v) => {
  2376. if (this.targetUser.left.includes(v.username)) {
  2377. if (v.floor > this.targetUser.rightFloor) {
  2378. if (v.replyUsers.includes(this.targetUser.right)) {
  2379. return true;
  2380. }
  2381. } else {
  2382. return true;
  2383. }
  2384. }
  2385. if (v.username === this.targetUser.right) {
  2386. for (let i = 0; i < this.targetUser.left.length; i++) {
  2387. if (v.replyUsers.includes(this.targetUser.left[i])) {
  2388. return true;
  2389. }
  2390. }
  2391. }
  2392. });
  2393. }
  2394. return [];
  2395. }
  2396. },
  2397. watch: {
  2398. "post.id"(n, o) {
  2399. if (this.$refs["post-editor"]) {
  2400. this.$refs["post-editor"].content = "";
  2401. }
  2402. },
  2403. modelValue: {
  2404. handler(newVal) {
  2405. if (this.isPost)
  2406. return;
  2407. if (newVal) {
  2408. document.body.style.overflow = "hidden";
  2409. this.read = this.post.read;
  2410. this.currentFloor = 1;
  2411. vue.nextTick(() => {
  2412. var _a, _b, _c, _d;
  2413. (_b = (_a = this.$refs) == null ? void 0 : _a.main) == null ? void 0 : _b.focus();
  2414. (_d = (_c = this.$refs) == null ? void 0 : _c.detail) == null ? void 0 : _d.scrollTo({ top: 0 });
  2415. });
  2416. } else {
  2417. this.$emit("saveReadList");
  2418. document.body.style.overflow = "unset";
  2419. this.isSticky = false;
  2420. this.showRelationReply = false;
  2421. if ((this.pageType === PageType.Home || this.pageType === PageType.Node) && window.location.pathname !== "/") {
  2422. window.history.back();
  2423. }
  2424. }
  2425. }
  2426. }
  2427. },
  2428. mounted() {
  2429. setTimeout(() => {
  2430. var _a;
  2431. this.postDetailWidth = ((_a = this.$refs.mainWrapper) == null ? void 0 : _a.getBoundingClientRect().width) || 0;
  2432. });
  2433. this.debounceScroll = debounce(this.scroll, 300, false);
  2434. if (this.isLogin) {
  2435. const observer = new IntersectionObserver(
  2436. ([e]) => e.target.toggleAttribute("stuck", e.intersectionRatio < 1),
  2437. { threshold: [1] }
  2438. );
  2439. observer.observe(this.$refs.replyBox);
  2440. window.addEventListener("keydown", this.onKeyDown);
  2441. }
  2442. eventBus.on(CMD.SHOW_CALL, (val) => {
  2443. if (val.show) {
  2444. this.showCallList = true;
  2445. this.replyText = val.text;
  2446. if (this.isPost) {
  2447. this.callStyle.top = val.top + $(window.win()).scrollTop() + -40 + "px";
  2448. } else {
  2449. this.callStyle.top = val.top + $(".post-detail").scrollTop() + 15 + "px";
  2450. }
  2451. this.callStyle.left = val.left - $(".main")[0].getBoundingClientRect().left + 10 + "px";
  2452. if (this.selectCallIndex >= this.filterCallList.length) {
  2453. this.selectCallIndex = 0;
  2454. }
  2455. } else {
  2456. this.replyText = "";
  2457. this.showCallList = false;
  2458. this.selectCallIndex = 0;
  2459. }
  2460. });
  2461. eventBus.on(CMD.RELATION_REPLY, (val) => {
  2462. this.targetUser = val;
  2463. this.showRelationReply = true;
  2464. });
  2465. eventBus.on(CMD.JUMP, this.jump);
  2466. if (this.isPost) {
  2467. window.addEventListener("scroll", this.debounceScroll);
  2468. }
  2469. },
  2470. beforeUnmount() {
  2471. window.removeEventListener("keydown", this.onKeyDown);
  2472. eventBus.off(CMD.SHOW_CALL);
  2473. },
  2474. methods: {
  2475. scroll() {
  2476. if (!this.config.rememberLastReadFloor)
  2477. return;
  2478. let height = window.innerHeight * 0.3;
  2479. let comments = $(".comments .comment");
  2480. let forCount = 0;
  2481. for (let i = 0; i < comments.length; i++) {
  2482. forCount++;
  2483. let ins = comments[i];
  2484. let rect = ins.getBoundingClientRect();
  2485. if (rect.top > height) {
  2486. let lastReadFloor = Number(ins.dataset["floor"]);
  2487. console.log("当前阅读楼层", lastReadFloor);
  2488. eventBus.emit(CMD.ADD_READ, {
  2489. floor: lastReadFloor > 3 ? lastReadFloor : 0,
  2490. total: this.post.replyList.length
  2491. });
  2492. if (lastReadFloor > 3) {
  2493. this.read.floor = 0;
  2494. }
  2495. break;
  2496. }
  2497. }
  2498. if (forCount === comments.length) {
  2499. console.log("看到最后了");
  2500. eventBus.emit(CMD.ADD_READ, {
  2501. floor: forCount,
  2502. total: this.post.replyList.length
  2503. });
  2504. }
  2505. },
  2506. stop(e) {
  2507. },
  2508. jump(floor) {
  2509. try {
  2510. floor = Number(floor);
  2511. } catch (e) {
  2512. }
  2513. if (!floor)
  2514. return;
  2515. if (!this.post.replyList.length) {
  2516. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "没有回复可跳转!" });
  2517. this.read.floor = 0;
  2518. return;
  2519. }
  2520. if (floor > this.post.replyList.length) {
  2521. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  2522. this.read.floor = 0;
  2523. return;
  2524. }
  2525. let comment = $(`.c_${floor}`);
  2526. if (!comment.length) {
  2527. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有找到对应回复!" });
  2528. this.read.floor = 0;
  2529. return;
  2530. }
  2531. comment[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
  2532. comment.addClass("ding");
  2533. this.read.floor = 0;
  2534. this.currentFloor = floor + 1;
  2535. setTimeout(() => {
  2536. comment.removeClass("ding");
  2537. }, 2e3);
  2538. },
  2539. jumpLastRead(floor) {
  2540. if (this.config.autoJumpLastReadFloor) {
  2541. if (!floor)
  2542. return;
  2543. setTimeout(() => {
  2544. console.log("上次跳转", floor);
  2545. this.jump(floor);
  2546. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "已跳转到上次阅读位置" });
  2547. }, 300);
  2548. }
  2549. },
  2550. collapseTopReplyList() {
  2551. $(this.$refs.topReply).slideToggle("fast");
  2552. },
  2553. goBottom() {
  2554. this.isSticky = false;
  2555. setTimeout(() => {
  2556. if (this.isPost) {
  2557. let body = $("body , html");
  2558. let scrollHeight = body.prop("scrollHeight");
  2559. body.animate({ scrollTop: scrollHeight - 850 }, 300);
  2560. } else {
  2561. this.$refs.detail.scrollTo({ top: this.$refs.detail.scrollHeight, behavior: "smooth" });
  2562. }
  2563. });
  2564. },
  2565. close(from) {
  2566. if (this.isPost)
  2567. return;
  2568. if (from === "space") {
  2569. if (this.config.closePostDetailBySpace) {
  2570. this.$emit("update:modelValue", false);
  2571. }
  2572. } else {
  2573. this.$emit("update:modelValue", false);
  2574. }
  2575. },
  2576. setCall(e) {
  2577. eventBus.emit(CMD.SET_CALL, e);
  2578. this.showCallList = false;
  2579. },
  2580. onKeyDown(e) {
  2581. if (!this.modelValue)
  2582. return;
  2583. if (!this.showCallList)
  2584. return;
  2585. let length = this.filterCallList.slice(0, 10).length;
  2586. if (e.keyCode === 13) {
  2587. this.setCall(this.filterCallList[this.selectCallIndex]);
  2588. e.preventDefault();
  2589. }
  2590. if (e.keyCode === 38) {
  2591. this.selectCallIndex--;
  2592. if (this.selectCallIndex < 0) {
  2593. this.selectCallIndex = length - 1;
  2594. }
  2595. e.preventDefault();
  2596. }
  2597. if (e.keyCode === 40) {
  2598. this.selectCallIndex++;
  2599. if (this.selectCallIndex > length - 1) {
  2600. this.selectCallIndex = 0;
  2601. }
  2602. e.preventDefault();
  2603. }
  2604. },
  2605. changeOption(item) {
  2606. this.$emit("update:displayType", item);
  2607. },
  2608. addThank() {
  2609. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "add" });
  2610. },
  2611. recallThank() {
  2612. eventBus.emit(CMD.CHANGE_POST_THANK, { id: this.post.id, type: "recall" });
  2613. },
  2614. scrollTop() {
  2615. if (this.isPost) {
  2616. $("body , html").animate({ scrollTop: 0 }, 300);
  2617. } else {
  2618. this.$refs.detail.scrollTo({ top: 0, behavior: "smooth" });
  2619. }
  2620. }
  2621. }
  2622. };
  2623. const _withScopeId$2 = (n) => (vue.pushScopeId("data-v-4038172d"), n = n(), vue.popScopeId(), n);
  2624. const _hoisted_1$5 = { class: "my-box post-wrapper" };
  2625. const _hoisted_2$4 = { class: "toolbar-wrapper" };
  2626. const _hoisted_3$3 = {
  2627. key: 0,
  2628. class: "my-box"
  2629. };
  2630. const _hoisted_4$1 = { class: "my-cell flex" };
  2631. const _hoisted_5$1 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "高赞回复", -1));
  2632. const _hoisted_6$1 = { class: "top-reply" };
  2633. const _hoisted_7 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-times" }, null, -1));
  2634. const _hoisted_8 = { ref: "topReply" };
  2635. const _hoisted_9 = { class: "my-box comment-wrapper" };
  2636. const _hoisted_10 = {
  2637. key: 0,
  2638. class: "my-cell flex"
  2639. };
  2640. const _hoisted_11 = {
  2641. key: 0,
  2642. class: "read-notice"
  2643. };
  2644. const _hoisted_12 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "上次打开:", -1));
  2645. const _hoisted_13 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  2646. const _hoisted_14 = [
  2647. _hoisted_13
  2648. ];
  2649. const _hoisted_15 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  2650. const _hoisted_16 = [
  2651. _hoisted_15
  2652. ];
  2653. const _hoisted_17 = { class: "my-cell flex" };
  2654. const _hoisted_18 = { class: "gray" };
  2655. const _hoisted_19 = { key: 0 };
  2656. const _hoisted_20 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("strong", { class: "snow" }, "•", -1));
  2657. const _hoisted_21 = ["innerHTML"];
  2658. const _hoisted_22 = {
  2659. key: 0,
  2660. class: "loading-wrapper"
  2661. };
  2662. const _hoisted_23 = {
  2663. key: 1,
  2664. class: "comments"
  2665. };
  2666. const _hoisted_24 = {
  2667. key: 1,
  2668. id: "no-comments-yet"
  2669. };
  2670. const _hoisted_25 = { class: "my-cell flex" };
  2671. const _hoisted_26 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", null, "添加一条新回复", -1));
  2672. const _hoisted_27 = { class: "notice-right" };
  2673. const _hoisted_28 = { class: "w" };
  2674. const _hoisted_29 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "gray" }, "上下文", -1));
  2675. const _hoisted_30 = { class: "top-reply" };
  2676. const _hoisted_31 = ["onClick"];
  2677. const _hoisted_32 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", {
  2678. class: "fa fa-times",
  2679. "aria-hidden": "true"
  2680. }, null, -1));
  2681. const _hoisted_33 = [
  2682. _hoisted_32
  2683. ];
  2684. const _hoisted_34 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", {
  2685. class: "fa fa-long-arrow-up",
  2686. "aria-hidden": "true"
  2687. }, null, -1));
  2688. const _hoisted_35 = [
  2689. _hoisted_34
  2690. ];
  2691. const _hoisted_36 = /* @__PURE__ */ _withScopeId$2(() => /* @__PURE__ */ vue.createElementVNode("i", { class: "fa fa-long-arrow-down" }, null, -1));
  2692. function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
  2693. const _component_BaseHtmlRender = vue.resolveComponent("BaseHtmlRender");
  2694. const _component_Point = vue.resolveComponent("Point");
  2695. const _component_Toolbar = vue.resolveComponent("Toolbar");
  2696. const _component_Tooltip = vue.resolveComponent("Tooltip");
  2697. const _component_PopConfirm = vue.resolveComponent("PopConfirm");
  2698. const _component_Comment = vue.resolveComponent("Comment");
  2699. const _component_PostEditor = vue.resolveComponent("PostEditor");
  2700. const _component_SingleComment = vue.resolveComponent("SingleComment");
  2701. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  2702. class: vue.normalizeClass(["post-detail", [$options.isNight ? "isNight" : "", $options.pageType]]),
  2703. ref: "detail",
  2704. onKeydown: _cache[23] || (_cache[23] = vue.withKeys(($event) => $options.close(), ["esc"])),
  2705. onScroll: _cache[24] || (_cache[24] = (...args) => $data.debounceScroll && $data.debounceScroll(...args)),
  2706. onClick: _cache[25] || (_cache[25] = ($event) => $options.close("space"))
  2707. }, [
  2708. vue.createElementVNode("div", {
  2709. ref: "main",
  2710. class: "main",
  2711. tabindex: "1",
  2712. onClick: _cache[22] || (_cache[22] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  2713. }, [
  2714. vue.createElementVNode("div", {
  2715. class: "main-wrapper",
  2716. ref: "mainWrapper",
  2717. style: vue.normalizeStyle({ width: $options.config.postWidth })
  2718. }, [
  2719. vue.createElementVNode("div", _hoisted_1$5, [
  2720. vue.createVNode(_component_BaseHtmlRender, {
  2721. html: $options.post.headerTemplate
  2722. }, null, 8, ["html"]),
  2723. vue.createElementVNode("div", _hoisted_2$4, [
  2724. vue.createVNode(_component_Point, {
  2725. onAddThank: $options.addThank,
  2726. onRecallThank: $options.recallThank,
  2727. full: false,
  2728. item: {
  2729. isThanked: $options.post.isThanked,
  2730. thankCount: $options.post.thankCount,
  2731. username: $options.post.username
  2732. },
  2733. "api-url": "topic/" + $options.post.id
  2734. }, null, 8, ["onAddThank", "onRecallThank", "item", "api-url"]),
  2735. vue.createVNode(_component_Toolbar, {
  2736. onReply: _cache[0] || (_cache[0] = ($event) => $data.isSticky = !$data.isSticky)
  2737. })
  2738. ])
  2739. ]),
  2740. $options.topReply.length && $options.config.showTopReply ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$3, [
  2741. vue.createElementVNode("div", _hoisted_4$1, [
  2742. _hoisted_5$1,
  2743. vue.createElementVNode("div", _hoisted_6$1, [
  2744. vue.createVNode(_component_Tooltip, {
  2745. title: `统计点赞数大于等于${$options.config.topReplyLoveMinCount}个的回复,可在设置中调整`
  2746. }, {
  2747. default: vue.withCtx(() => [
  2748. vue.createElementVNode("i", {
  2749. class: "fa fa-info",
  2750. onClick: _cache[1] || (_cache[1] = ($event) => $options.showConfig())
  2751. })
  2752. ]),
  2753. _: 1
  2754. }, 8, ["title"]),
  2755. vue.createVNode(_component_PopConfirm, {
  2756. title: "关闭后不再默认显示,可在设置里重新打开,确认关闭?",
  2757. onConfirm: _cache[2] || (_cache[2] = ($event) => $options.config.showTopReply = false)
  2758. }, {
  2759. default: vue.withCtx(() => [
  2760. _hoisted_7
  2761. ]),
  2762. _: 1
  2763. }),
  2764. vue.createVNode(_component_Tooltip, { title: "收起高赞回复" }, {
  2765. default: vue.withCtx(() => [
  2766. vue.createElementVNode("i", {
  2767. class: "fa fa-compress",
  2768. onClick: _cache[3] || (_cache[3] = (...args) => $options.collapseTopReplyList && $options.collapseTopReplyList(...args))
  2769. })
  2770. ]),
  2771. _: 1
  2772. })
  2773. ])
  2774. ]),
  2775. vue.createElementVNode("div", _hoisted_8, [
  2776. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.topReply, (item, index2) => {
  2777. return vue.openBlock(), vue.createBlock(_component_Comment, {
  2778. key: item.floor,
  2779. type: "top",
  2780. modelValue: $options.topReply[index2],
  2781. "onUpdate:modelValue": ($event) => $options.topReply[index2] = $event
  2782. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  2783. }), 128))
  2784. ], 512)
  2785. ])) : vue.createCommentVNode("", true),
  2786. vue.createElementVNode("div", _hoisted_9, [
  2787. $options.post.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  2788. $options.config.showToolbar ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10, [
  2789. vue.createElementVNode("div", {
  2790. class: vue.normalizeClass(["radio-group2", { isNight: $options.isNight }])
  2791. }, [
  2792. vue.createElementVNode("div", {
  2793. class: vue.normalizeClass(["radio", $props.displayType === 0 ? "active" : ""]),
  2794. onClick: _cache[4] || (_cache[4] = ($event) => $options.changeOption(0))
  2795. }, "楼中楼 ", 2),
  2796. vue.createElementVNode("div", {
  2797. class: vue.normalizeClass(["radio", $props.displayType === 1 ? "active" : ""]),
  2798. onClick: _cache[5] || (_cache[5] = ($event) => $options.changeOption(1))
  2799. }, "感谢 ", 2),
  2800. vue.createElementVNode("div", {
  2801. class: vue.normalizeClass(["radio", $props.displayType === 3 ? "active" : ""]),
  2802. onClick: _cache[6] || (_cache[6] = ($event) => $options.changeOption(3))
  2803. }, "只看楼主 ", 2),
  2804. vue.createElementVNode("div", {
  2805. class: vue.normalizeClass(["radio", $props.displayType === 2 ? "active" : ""]),
  2806. onClick: _cache[7] || (_cache[7] = ($event) => $options.changeOption(2))
  2807. }, "V2原版 ", 2)
  2808. ], 2),
  2809. $data.read.floor || $data.read.total ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11, [
  2810. _hoisted_12,
  2811. $data.read.floor ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  2812. vue.createElementVNode("span", null, [
  2813. vue.createTextVNode("阅读到"),
  2814. vue.createElementVNode("b", null, vue.toDisplayString($data.read.floor), 1),
  2815. vue.createTextVNode("楼")
  2816. ]),
  2817. vue.createElementVNode("div", {
  2818. class: "jump jump1",
  2819. onClick: _cache[8] || (_cache[8] = ($event) => $options.jump($data.read.floor))
  2820. }, _hoisted_14)
  2821. ], 64)) : vue.createCommentVNode("", true),
  2822. vue.createElementVNode("span", null, [
  2823. vue.createTextVNode("总楼层"),
  2824. vue.createElementVNode("b", null, vue.toDisplayString($data.read.total), 1)
  2825. ]),
  2826. vue.createElementVNode("div", {
  2827. class: "jump",
  2828. onClick: _cache[9] || (_cache[9] = ($event) => $options.jump($data.read.total))
  2829. }, _hoisted_16)
  2830. ])) : vue.createCommentVNode("", true)
  2831. ])) : vue.createCommentVNode("", true),
  2832. vue.createElementVNode("div", _hoisted_17, [
  2833. vue.createElementVNode("span", _hoisted_18, [
  2834. vue.createTextVNode(vue.toDisplayString($options.post.replyCount) + " 条回复 ", 1),
  2835. $options.post.createDate ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_19, [
  2836. vue.createTextVNode("  "),
  2837. _hoisted_20,
  2838. vue.createTextVNode("  " + vue.toDisplayString($options.post.createDate), 1)
  2839. ])) : vue.createCommentVNode("", true)
  2840. ]),
  2841. vue.createElementVNode("div", {
  2842. class: "fr",
  2843. innerHTML: $options.post.fr
  2844. }, null, 8, _hoisted_21)
  2845. ])
  2846. ], 64)) : vue.createCommentVNode("", true),
  2847. $options.replyList.length || $props.loading ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  2848. $props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_22, [
  2849. vue.createElementVNode("div", {
  2850. class: vue.normalizeClass([$options.isNight ? "loading-b" : "loading-c"])
  2851. }, null, 2)
  2852. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_23, [
  2853. $props.modelValue ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 0 }, vue.renderList($options.replyList, (item, index2) => {
  2854. return vue.openBlock(), vue.createBlock(_component_Comment, {
  2855. key: item.floor,
  2856. modelValue: $options.replyList[index2],
  2857. "onUpdate:modelValue": ($event) => $options.replyList[index2] = $event
  2858. }, null, 8, ["modelValue", "onUpdate:modelValue"]);
  2859. }), 128)) : vue.createCommentVNode("", true)
  2860. ]))
  2861. ], 64)) : vue.createCommentVNode("", true)
  2862. ]),
  2863. !($options.replyList.length || $props.loading) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_24, "目前尚无回复")) : vue.createCommentVNode("", true),
  2864. $options.isLogin ? (vue.openBlock(), vue.createElementBlock("div", {
  2865. key: 2,
  2866. class: vue.normalizeClass(["my-box editor-wrapper", { "sticky": $data.isSticky }]),
  2867. ref: "replyBox"
  2868. }, [
  2869. vue.createElementVNode("div", _hoisted_25, [
  2870. _hoisted_26,
  2871. vue.createElementVNode("div", _hoisted_27, [
  2872. $data.isSticky ? (vue.openBlock(), vue.createElementBlock("a", {
  2873. key: 0,
  2874. class: "float",
  2875. onClick: _cache[10] || (_cache[10] = ($event) => $data.isSticky = false)
  2876. }, "取消回复框停靠")) : vue.createCommentVNode("", true),
  2877. vue.createElementVNode("a", {
  2878. onClick: _cache[11] || (_cache[11] = (...args) => $options.scrollTop && $options.scrollTop(...args))
  2879. }, "回到顶部")
  2880. ])
  2881. ]),
  2882. vue.createElementVNode("div", _hoisted_28, [
  2883. vue.createVNode(_component_PostEditor, {
  2884. onClose: $options.goBottom,
  2885. ref: "post-editor",
  2886. useType: "reply-post",
  2887. onClick: _cache[12] || (_cache[12] = ($event) => $data.isSticky = true)
  2888. }, null, 8, ["onClose"])
  2889. ])
  2890. ], 2)) : vue.createCommentVNode("", true)
  2891. ], 4),
  2892. $data.showRelationReply ? (vue.openBlock(), vue.createElementBlock("div", {
  2893. key: 0,
  2894. class: "relationReply",
  2895. onClick: _cache[16] || (_cache[16] = ($event) => $options.close("space"))
  2896. }, [
  2897. vue.createElementVNode("div", {
  2898. class: "my-cell flex",
  2899. onClick: _cache[14] || (_cache[14] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  2900. }, [
  2901. _hoisted_29,
  2902. vue.createElementVNode("div", _hoisted_30, [
  2903. vue.createElementVNode("i", {
  2904. class: "fa fa-times",
  2905. onClick: _cache[13] || (_cache[13] = ($event) => $data.showRelationReply = false)
  2906. })
  2907. ])
  2908. ]),
  2909. vue.createElementVNode("div", {
  2910. class: "comments",
  2911. onClick: _cache[15] || (_cache[15] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  2912. }, [
  2913. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.relationReply, (item, index2) => {
  2914. return vue.openBlock(), vue.createBlock(_component_SingleComment, {
  2915. "is-right": item.username === $data.targetUser.right,
  2916. key: item.floor,
  2917. comment: item
  2918. }, null, 8, ["is-right", "comment"]);
  2919. }), 128))
  2920. ])
  2921. ])) : vue.createCommentVNode("", true),
  2922. $data.showCallList && $options.filterCallList.length ? (vue.openBlock(), vue.createElementBlock("div", {
  2923. key: 1,
  2924. class: "call-list",
  2925. style: vue.normalizeStyle($data.callStyle)
  2926. }, [
  2927. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList($options.filterCallList.slice(0, 10), (item, index2) => {
  2928. return vue.openBlock(), vue.createElementBlock("div", {
  2929. class: vue.normalizeClass(["call-item", { select: index2 === $data.selectCallIndex }]),
  2930. onClick: ($event) => $options.setCall(item)
  2931. }, [
  2932. vue.createElementVNode("a", null, vue.toDisplayString(item), 1)
  2933. ], 10, _hoisted_31);
  2934. }), 256))
  2935. ], 4)) : vue.createCommentVNode("", true),
  2936. $options.config.closePostDetailBySpace ? (vue.openBlock(), vue.createElementBlock("div", {
  2937. key: 2,
  2938. class: "close-btn",
  2939. onClick: _cache[17] || (_cache[17] = ($event) => $options.close("btn"))
  2940. }, _hoisted_33)) : vue.createCommentVNode("", true),
  2941. vue.createElementVNode("div", {
  2942. class: "scroll-top button",
  2943. onClick: _cache[18] || (_cache[18] = vue.withModifiers((...args) => $options.scrollTop && $options.scrollTop(...args), ["stop"]))
  2944. }, _hoisted_35),
  2945. vue.createElementVNode("div", {
  2946. class: "scroll-to button",
  2947. onClick: _cache[21] || (_cache[21] = vue.withModifiers(($event) => $options.jump($data.currentFloor), ["stop"]))
  2948. }, [
  2949. _hoisted_36,
  2950. vue.withDirectives(vue.createElementVNode("input", {
  2951. type: "text",
  2952. "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => $data.currentFloor = $event),
  2953. onClick: _cache[20] || (_cache[20] = vue.withModifiers((...args) => $options.stop && $options.stop(...args), ["stop"]))
  2954. }, null, 512), [
  2955. [vue.vModelText, $data.currentFloor]
  2956. ])
  2957. ])
  2958. ], 512)
  2959. ], 34)), [
  2960. [vue.vShow, $props.modelValue]
  2961. ]);
  2962. }
  2963. const PostDetail = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$2], ["__scopeId", "data-v-4038172d"]]);
  2964. const _withScopeId$1 = (n) => (vue.pushScopeId("data-v-19fe372d"), n = n(), vue.popScopeId(), n);
  2965. const _hoisted_1$4 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("svg", {
  2966. width: "24",
  2967. height: "24",
  2968. viewBox: "0 0 48 48",
  2969. fill: "none",
  2970. xmlns: "http://www.w3.org/2000/svg"
  2971. }, [
  2972. /* @__PURE__ */ vue.createElementVNode("path", {
  2973. d: "M17 32L19.1875 27M31 32L28.8125 27M19.1875 27L24 16L28.8125 27M19.1875 27H28.8125",
  2974. stroke: "#929596",
  2975. "stroke-width": "4",
  2976. "stroke-linecap": "round",
  2977. "stroke-linejoin": "round"
  2978. }),
  2979. /* @__PURE__ */ vue.createElementVNode("path", {
  2980. d: "M43.1999 20C41.3468 10.871 33.2758 4 23.5999 4C13.9241 4 5.85308 10.871 4 20L10 18",
  2981. stroke: "#929596",
  2982. "stroke-width": "4",
  2983. "stroke-linecap": "round",
  2984. "stroke-linejoin": "round"
  2985. }),
  2986. /* @__PURE__ */ vue.createElementVNode("path", {
  2987. d: "M4 28C5.85308 37.129 13.9241 44 23.5999 44C33.2758 44 41.3468 37.129 43.1999 28L38 30",
  2988. stroke: "#929596",
  2989. "stroke-width": "4",
  2990. "stroke-linecap": "round",
  2991. "stroke-linejoin": "round"
  2992. })
  2993. ], -1));
  2994. const _hoisted_2$3 = { key: 1 };
  2995. const _sfc_main$4 = {
  2996. __name: "Base64Tooltip",
  2997. setup(__props) {
  2998. const tooltip = vue.ref(null);
  2999. const show = vue.ref(false);
  3000. const originalText = vue.ref("");
  3001. const decodeText = vue.ref("");
  3002. const styleObject = vue.reactive({
  3003. left: "-100vw",
  3004. top: "-100vh"
  3005. });
  3006. vue.onMounted(() => {
  3007. eventBus.on(CMD.SHOW_TOOLTIP, ({ text, e }) => {
  3008. setTimeout(() => show.value = true);
  3009. originalText.value = text;
  3010. decodeText.value = "";
  3011. styleObject.left = e.clientX + "px";
  3012. styleObject.top = e.clientY + 20 + "px";
  3013. });
  3014. window.addEventListener("click", (e) => {
  3015. if (!tooltip.value)
  3016. return;
  3017. if (!tooltip.value.contains(e.target) && show.value) {
  3018. show.value = false;
  3019. }
  3020. }, { capture: true });
  3021. const fn = () => show.value && (show.value = false);
  3022. $(".post-detail", window.win().doc).on("scroll", fn);
  3023. });
  3024. function copy() {
  3025. if (window.win().navigator.clipboard) {
  3026. window.win().navigator.clipboard.writeText(decodeText.value);
  3027. eventBus.emit(CMD.SHOW_MSG, { type: "success", text: "复制成功" });
  3028. } else {
  3029. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "复制失败!浏览器不支持!" });
  3030. }
  3031. }
  3032. function base64ToArrayBuffer(base64) {
  3033. let binary_string = window.atob(base64);
  3034. let len = binary_string.length;
  3035. let bytes = new Uint8Array(len);
  3036. for (let i = 0; i < len; i++) {
  3037. bytes[i] = binary_string.charCodeAt(i);
  3038. }
  3039. return bytes.buffer;
  3040. }
  3041. function decode() {
  3042. try {
  3043. new Blob([base64ToArrayBuffer(originalText.value)]).text().then((r) => {
  3044. decodeText.value = r;
  3045. });
  3046. } catch (e) {
  3047. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "Base64解码失败!不是标准数据!" });
  3048. }
  3049. }
  3050. return (_ctx, _cache) => {
  3051. return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", {
  3052. class: "base64_tooltip",
  3053. style: vue.normalizeStyle(styleObject),
  3054. onClick: decode,
  3055. ref_key: "tooltip",
  3056. ref: tooltip
  3057. }, [
  3058. !decodeText.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
  3059. vue.createTextVNode(" Base64解码:" + vue.toDisplayString(originalText.value) + " ", 1),
  3060. _hoisted_1$4
  3061. ], 64)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$3, [
  3062. vue.createElementVNode("span", null, vue.toDisplayString(decodeText.value), 1),
  3063. vue.createElementVNode("div", {
  3064. class: "button",
  3065. onClick: copy
  3066. }, "点击复制")
  3067. ]))
  3068. ], 4)), [
  3069. [vue.vShow, show.value]
  3070. ]);
  3071. };
  3072. }
  3073. };
  3074. const Base64Tooltip = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-19fe372d"]]);
  3075. const _sfc_main$3 = {
  3076. name: "Msg",
  3077. props: {
  3078. type: "",
  3079. text: ""
  3080. },
  3081. created() {
  3082. setTimeout(() => {
  3083. this.$emit("close");
  3084. }, 3e3);
  3085. }
  3086. };
  3087. const _hoisted_1$3 = /* @__PURE__ */ vue.createElementVNode("svg", {
  3088. width: "24",
  3089. height: "24",
  3090. viewBox: "0 0 48 48",
  3091. fill: "none",
  3092. xmlns: "http://www.w3.org/2000/svg"
  3093. }, [
  3094. /* @__PURE__ */ vue.createElementVNode("path", {
  3095. d: "M14 14L34 34",
  3096. stroke: "#ffffff",
  3097. "stroke-width": "4",
  3098. "stroke-linecap": "round",
  3099. "stroke-linejoin": "round"
  3100. }),
  3101. /* @__PURE__ */ vue.createElementVNode("path", {
  3102. d: "M14 34L34 14",
  3103. stroke: "#ffffff",
  3104. "stroke-width": "4",
  3105. "stroke-linecap": "round",
  3106. "stroke-linejoin": "round"
  3107. })
  3108. ], -1);
  3109. const _hoisted_2$2 = [
  3110. _hoisted_1$3
  3111. ];
  3112. const _hoisted_3$2 = { class: "right" };
  3113. function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
  3114. return vue.openBlock(), vue.createElementBlock("div", {
  3115. class: vue.normalizeClass(["msg", $props.type])
  3116. }, [
  3117. vue.createElementVNode("div", {
  3118. class: "left",
  3119. onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
  3120. }, _hoisted_2$2),
  3121. vue.createElementVNode("div", _hoisted_3$2, vue.toDisplayString($props.text), 1)
  3122. ], 2);
  3123. }
  3124. const Msg = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$1]]);
  3125. const _withScopeId = (n) => (vue.pushScopeId("data-v-b28a2e5e"), n = n(), vue.popScopeId(), n);
  3126. const _hoisted_1$2 = { class: "wrapper" };
  3127. const _hoisted_2$1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "title" }, " 添加标签 ", -1));
  3128. const _hoisted_3$1 = { class: "option" };
  3129. const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "用户:", -1));
  3130. const _hoisted_5 = ["onKeydown"];
  3131. const _hoisted_6 = { class: "btns" };
  3132. const _sfc_main$2 = {
  3133. __name: "TagModal",
  3134. props: ["tags"],
  3135. emits: ["update:tags"],
  3136. setup(__props, { emit }) {
  3137. const props = __props;
  3138. const tagModal = vue.reactive({
  3139. show: false,
  3140. currentUsername: "",
  3141. tag: ""
  3142. });
  3143. const isNight = vue.inject("isNight");
  3144. const input = vue.ref < HTMLInputElement > null;
  3145. vue.onMounted(() => {
  3146. eventBus.on(CMD.ADD_TAG, (username) => {
  3147. tagModal.currentUsername = username;
  3148. tagModal.show = true;
  3149. vue.nextTick(() => {
  3150. input.value.focus();
  3151. });
  3152. });
  3153. });
  3154. async function addTag() {
  3155. let oldTag = window.clone(props.tags);
  3156. let tempTag = window.clone(props.tags);
  3157. let userTags = tempTag[tagModal.currentUsername] ?? [];
  3158. let rIndex = userTags.findIndex((v) => v === tagModal.tag);
  3159. if (rIndex > -1) {
  3160. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "标签已存在!" });
  3161. return;
  3162. } else {
  3163. userTags.push(tagModal.tag);
  3164. }
  3165. tempTag[tagModal.currentUsername] = userTags;
  3166. emit("update:tags", tempTag);
  3167. tagModal.tag = "";
  3168. tagModal.show = false;
  3169. let res = await window.parse.saveTags(tempTag);
  3170. if (!res) {
  3171. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签添加失败!" });
  3172. emit("update:tags", oldTag);
  3173. }
  3174. }
  3175. return (_ctx, _cache) => {
  3176. return vue.openBlock(), vue.createBlock(vue.Transition, null, {
  3177. default: vue.withCtx(() => [
  3178. tagModal.show ? (vue.openBlock(), vue.createElementBlock("div", {
  3179. key: 0,
  3180. class: vue.normalizeClass(["tag-modal modal", { isNight: vue.unref(isNight) }])
  3181. }, [
  3182. vue.createElementVNode("div", {
  3183. class: "mask",
  3184. onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => tagModal.show = false, ["stop"]))
  3185. }),
  3186. vue.createElementVNode("div", _hoisted_1$2, [
  3187. _hoisted_2$1,
  3188. vue.createElementVNode("div", _hoisted_3$1, [
  3189. _hoisted_4,
  3190. vue.createElementVNode("div", null, vue.toDisplayString(tagModal.currentUsername), 1)
  3191. ]),
  3192. vue.withDirectives(vue.createElementVNode("input", {
  3193. type: "text",
  3194. ref: "input",
  3195. style: { "width": "100%" },
  3196. autofocus: "",
  3197. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tagModal.tag = $event),
  3198. onKeydown: vue.withKeys(addTag, ["enter"])
  3199. }, null, 40, _hoisted_5), [
  3200. [vue.vModelText, tagModal.tag]
  3201. ]),
  3202. vue.createElementVNode("div", _hoisted_6, [
  3203. vue.createElementVNode("div", {
  3204. class: "white",
  3205. onClick: _cache[2] || (_cache[2] = ($event) => tagModal.show = false)
  3206. }, "取消"),
  3207. vue.createElementVNode("div", {
  3208. class: "main",
  3209. onClick: addTag
  3210. }, "确定")
  3211. ])
  3212. ])
  3213. ], 2)) : vue.createCommentVNode("", true)
  3214. ]),
  3215. _: 1
  3216. });
  3217. };
  3218. }
  3219. };
  3220. const TagModal = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-b28a2e5e"]]);
  3221. const _hoisted_1$1 = { class: "msgs" };
  3222. const _sfc_main$1 = {
  3223. __name: "MsgModal",
  3224. setup(__props) {
  3225. const msgList = vue.reactive([
  3226. // {type: 'success', text: '123', id: Date.now()}
  3227. ]);
  3228. vue.onMounted(() => {
  3229. eventBus.on(CMD.SHOW_MSG, (val) => {
  3230. msgList.push({ ...val, id: Date.now() });
  3231. });
  3232. });
  3233. function removeMsg(id) {
  3234. let rIndex = msgList.findIndex((item) => item.id === id);
  3235. if (rIndex > -1) {
  3236. msgList.splice(rIndex, 1);
  3237. }
  3238. }
  3239. return (_ctx, _cache) => {
  3240. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
  3241. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(msgList, (v) => {
  3242. return vue.openBlock(), vue.createBlock(Msg, {
  3243. key: v.id,
  3244. type: v.type,
  3245. text: v.text,
  3246. onClose: ($event) => removeMsg(v.id)
  3247. }, null, 8, ["type", "text", "onClose"]);
  3248. }), 128))
  3249. ]);
  3250. };
  3251. }
  3252. };
  3253. const MsgModal = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-95974c3e"]]);
  3254. const _sfc_main = {
  3255. components: { MsgModal, TagModal, Tooltip, Setting, PostDetail, Base64Tooltip, Msg },
  3256. provide() {
  3257. return {
  3258. isLogin: vue.computed(() => this.isLogin),
  3259. isNight: vue.computed(() => this.isNight),
  3260. pageType: vue.computed(() => this.pageType),
  3261. tags: vue.computed(() => this.tags),
  3262. show: vue.computed(() => this.show),
  3263. post: vue.computed(() => this.current),
  3264. config: vue.computed(() => this.config),
  3265. allReplyUsers: vue.computed(() => {
  3266. var _a, _b, _c;
  3267. if ((_a = this.current) == null ? void 0 : _a.replyList) {
  3268. return Array.from(new Set(((_c = (_b = this.current) == null ? void 0 : _b.replyList) == null ? void 0 : _c.map((v) => v.username)) ?? []));
  3269. }
  3270. return [];
  3271. }),
  3272. showConfig: this.showConfig
  3273. };
  3274. },
  3275. data() {
  3276. return {
  3277. loading: window.pageType === PageType.Post,
  3278. loadMore: false,
  3279. isLogin: !!window.user.username,
  3280. pageType: window.pageType,
  3281. isNight: window.isNight,
  3282. stopMe: false,
  3283. //停止使用脚本
  3284. show: false,
  3285. current: window.clone(window.initPost),
  3286. list: [],
  3287. config: window.clone(window.config),
  3288. tags: window.user.tags,
  3289. readList: window.user.readList,
  3290. configModal: {
  3291. show: false
  3292. },
  3293. tagModal: {
  3294. show: false,
  3295. currentUsername: "",
  3296. tag: ""
  3297. }
  3298. };
  3299. },
  3300. computed: {
  3301. isList() {
  3302. return this.pageType !== PageType.Post;
  3303. },
  3304. isPost() {
  3305. return this.pageType === PageType.Post;
  3306. }
  3307. },
  3308. watch: {
  3309. "current.replyList": {
  3310. handler(newVal, oldVal) {
  3311. if (newVal.length) {
  3312. this.current.replyCount = newVal.length;
  3313. let res = window.parse.createNestedList(newVal, this.current.allReplyUsers);
  3314. if (res) {
  3315. this.current.nestedReplies = res;
  3316. }
  3317. } else {
  3318. this.current.replyCount = 0;
  3319. this.current.nestedReplies = [];
  3320. }
  3321. if (this.list) {
  3322. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  3323. if (rIndex > -1) {
  3324. this.list[rIndex].replyCount = newVal.length;
  3325. }
  3326. }
  3327. },
  3328. deep: true
  3329. },
  3330. config: {
  3331. handler(newVal) {
  3332. let config2 = { [window.user.username ?? "default"]: newVal };
  3333. localStorage.setItem("v2ex-config", JSON.stringify(config2));
  3334. window.config = newVal;
  3335. },
  3336. deep: true
  3337. },
  3338. tags(newVal) {
  3339. window.user.tags = newVal;
  3340. },
  3341. "config.viewType"(newVal) {
  3342. if (!newVal)
  3343. return;
  3344. if (newVal === "card") {
  3345. $(".post-item").each(function() {
  3346. $(this).addClass("preview");
  3347. });
  3348. } else {
  3349. $(".post-item").each(function() {
  3350. $(this).removeClass("preview");
  3351. });
  3352. }
  3353. }
  3354. },
  3355. created() {
  3356. window.cb = this.winCb;
  3357. if (window.win().canParseV2exPage) {
  3358. if (this.isList)
  3359. ;
  3360. }
  3361. $(document).on("click", "a", (e) => {
  3362. if (this.stopMe)
  3363. return true;
  3364. let { href, id, title } = window.parse.parseA(e.currentTarget);
  3365. if (this.clickPost(e, id, href, title)) {
  3366. return false;
  3367. }
  3368. });
  3369. let that = this;
  3370. $(document).on("click", ".post-item", function(e) {
  3371. if (this.classList.contains("preview")) {
  3372. if (e.target.tagName !== "A" && e.target.tagName !== "IMG" && !e.target.classList.contains("toggle")) {
  3373. console.log("点空白处");
  3374. let id = this.dataset["id"];
  3375. let href = this.dataset["href"];
  3376. if (that.clickPost(e, id, href)) {
  3377. return false;
  3378. } else {
  3379. location.href = href;
  3380. }
  3381. }
  3382. }
  3383. });
  3384. $(document).on("click", ".toggle", (e) => {
  3385. let id = e.currentTarget.dataset["id"];
  3386. let itemDom = window.win().query(`.id_${id}`);
  3387. if (itemDom.classList.contains("preview")) {
  3388. itemDom.classList.remove("preview");
  3389. } else {
  3390. itemDom.classList.add("preview");
  3391. }
  3392. });
  3393. window.onpopstate = (event) => {
  3394. if (event.state) {
  3395. if (!this.show)
  3396. this.show = true;
  3397. } else {
  3398. if (this.show)
  3399. this.show = false;
  3400. }
  3401. };
  3402. window.onbeforeunload = () => {
  3403. this.saveReadList();
  3404. };
  3405. this.initEvent();
  3406. },
  3407. beforeUnmount() {
  3408. eventBus.clear();
  3409. },
  3410. methods: {
  3411. saveReadList() {
  3412. window.parse.saveReadList(this.readList);
  3413. },
  3414. clickPost(e, id, href, title = "") {
  3415. var _a, _b, _c, _d, _e, _f;
  3416. if (id) {
  3417. if (this.config.clickPostItemOpenDetail) {
  3418. let index2 = this.list.findIndex((v) => v.id == id);
  3419. let postItem = this.clone(window.initPost);
  3420. if (index2 > -1) {
  3421. postItem = this.list[index2];
  3422. } else {
  3423. postItem.title = title ?? "加载中";
  3424. }
  3425. postItem.id = id;
  3426. postItem.href = href;
  3427. if (!postItem.headerTemplate) {
  3428. let template = `
  3429. <div class="header">
  3430. <div class="fr">
  3431. <a href="/member/${((_a = postItem == null ? void 0 : postItem.member) == null ? void 0 : _a.username) ?? ""}">
  3432. <img src="${((_b = postItem == null ? void 0 : postItem.member) == null ? void 0 : _b.avatar_large) ?? ""}" class="avatar"
  3433. border="0"
  3434. align="default" width="73" style="width: 73px; max-height: 73px;" alt="${((_c = postItem == null ? void 0 : postItem.member) == null ? void 0 : _c.username) ?? ""}">
  3435. </a>
  3436. </div>
  3437. <a href="/public">V2EX</a> <span class="chevron">&nbsp;›&nbsp;</span> <a href="${((_d = postItem == null ? void 0 : postItem.node) == null ? void 0 : _d.url) ?? ""}">${((_e = postItem == null ? void 0 : postItem.node) == null ? void 0 : _e.title) ?? ""}</a>
  3438. <div class="sep10"></div>
  3439. <h1>${(postItem == null ? void 0 : postItem.title) || "加载中..."}</h1>
  3440. <div id="topic_930514_votes" class="votes">
  3441. <a href="javascript:" onclick="null" class="vote">
  3442. <li class="fa fa-chevron-up"></li>
  3443. &nbsp;
  3444. </a> &nbsp;
  3445. <a href="javascript:" onclick="null" class="vote">
  3446. <li class="fa fa-chevron-down"></li>
  3447. </a>
  3448. </div> &nbsp;
  3449. <small class="gray">
  3450. <a href="/member/zyronon">${((_f = postItem == null ? void 0 : postItem.member) == null ? void 0 : _f.username) ?? ""}</a> ·
  3451. <span title="2023-04-07 11:32:28 +08:00">1 天前</span> · 0 次点击
  3452. </small>
  3453. </div>
  3454. <div class="cell">
  3455. <div class="topic_content">
  3456. <div class="markdown_body">
  3457. ${(postItem == null ? void 0 : postItem.content_rendered) ?? ""}
  3458. </div>
  3459. </div>
  3460. </div>
  3461. `;
  3462. postItem.headerTemplate = template;
  3463. }
  3464. this.getPostDetail(postItem);
  3465. e.preventDefault();
  3466. return true;
  3467. }
  3468. if (this.config.newTabOpen) {
  3469. let tempId = "a_blank_" + Date.now();
  3470. let a = win().doc.createElement("a");
  3471. a.setAttribute("href", href);
  3472. a.setAttribute("target", "_blank");
  3473. a.setAttribute("id", tempId);
  3474. if (!win().doc.getElementById(tempId)) {
  3475. win().doc.body.appendChild(a);
  3476. }
  3477. a.click();
  3478. return true;
  3479. }
  3480. }
  3481. },
  3482. showPost() {
  3483. this.show = true;
  3484. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  3485. $(this).hide();
  3486. });
  3487. },
  3488. showConfig() {
  3489. this.configModal.show = true;
  3490. },
  3491. async winCb({ type, value }) {
  3492. if (type === "openSetting") {
  3493. this.configModal.show = true;
  3494. }
  3495. if (type === "restorePost") {
  3496. if (this.stopMe)
  3497. return;
  3498. this.stopMe = true;
  3499. this.show = false;
  3500. this.loading = false;
  3501. eventBus.emit(CMD.SHOW_MSG, { type: "warning", text: "脚本无法查看此页面!" });
  3502. $(`#Wrapper #Main .box:lt(3)`).each(function() {
  3503. $(this).show();
  3504. });
  3505. }
  3506. if (type === "postContent") {
  3507. if (this.stopMe)
  3508. return;
  3509. this.current = Object.assign(this.clone(this.current), this.clone(value));
  3510. if (this.config.autoOpenDetail) {
  3511. this.showPost();
  3512. }
  3513. }
  3514. if (type === "postReplies") {
  3515. if (this.stopMe)
  3516. return;
  3517. this.current = Object.assign(this.clone(this.current), this.clone(value));
  3518. console.log("当前帖子", this.current);
  3519. this.loading = false;
  3520. }
  3521. if (type === "syncData") {
  3522. this.list = window.postList;
  3523. this.config = window.config;
  3524. this.tags = window.user.tags;
  3525. this.readList = window.user.readList;
  3526. this.current.read = this.readList[this.current.id] ?? {};
  3527. if (this.show && this.isPost && this.current.read.floor) {
  3528. this.$refs.postDetail.read = this.current.read;
  3529. }
  3530. console.log("this.readList", this.readList);
  3531. }
  3532. },
  3533. clone(val) {
  3534. return window.clone(val);
  3535. },
  3536. initEvent() {
  3537. eventBus.on(CMD.CHANGE_COMMENT_THANK, (val) => {
  3538. console.log("CHANGE_COMMENT_THANK", val);
  3539. const { id, type } = val;
  3540. let currentI = this.current.replyList.findIndex((i) => i.id === id);
  3541. if (currentI > -1) {
  3542. this.current.replyList[currentI].isThanked = type === "add";
  3543. if (type === "add") {
  3544. this.current.replyList[currentI].thankCount++;
  3545. } else {
  3546. this.current.replyList[currentI].thankCount--;
  3547. }
  3548. }
  3549. });
  3550. eventBus.on(CMD.CHANGE_POST_THANK, (val) => {
  3551. const { id, type } = val;
  3552. this.current.isThanked = type === "add";
  3553. if (type === "add") {
  3554. this.current.thankCount++;
  3555. } else {
  3556. this.current.thankCount--;
  3557. }
  3558. let currentI = this.list.findIndex((i) => i.id === id);
  3559. if (currentI > -1) {
  3560. this.list[currentI].isThanked = type === "add";
  3561. if (type === "add") {
  3562. this.list[currentI].thankCount++;
  3563. } else {
  3564. this.list[currentI].thankCount++;
  3565. }
  3566. }
  3567. });
  3568. eventBus.on(CMD.REMOVE, (val) => {
  3569. let removeIndex = this.current.replyList.findIndex((i) => i.floor === val);
  3570. if (removeIndex > -1) {
  3571. this.current.replyList.splice(removeIndex, 1);
  3572. }
  3573. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  3574. if (rIndex > -1) {
  3575. this.list[rIndex] = Object.assign(this.list[rIndex], val);
  3576. }
  3577. });
  3578. eventBus.on(CMD.IGNORE, () => {
  3579. this.show = false;
  3580. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  3581. if (rIndex > -1) {
  3582. this.list.splice(rIndex, 1);
  3583. }
  3584. this.current = this.clone(window.initPost);
  3585. });
  3586. eventBus.on(CMD.MERGE, (val) => {
  3587. this.current = Object.assign(this.current, val);
  3588. let rIndex = this.list.findIndex((i) => i.id === this.current.id);
  3589. if (rIndex > -1) {
  3590. this.list[rIndex] = Object.assign(this.list[rIndex], val);
  3591. }
  3592. });
  3593. eventBus.on(CMD.ADD_READ, (val) => {
  3594. this.readList[this.current.id] = val;
  3595. });
  3596. eventBus.on(CMD.ADD_REPLY, (item) => {
  3597. this.current.replyList.push(item);
  3598. });
  3599. eventBus.on(CMD.REFRESH_ONCE, async (once) => {
  3600. if (once) {
  3601. if (typeof once === "string") {
  3602. let res = once.match(/var once = "([\d]+)";/);
  3603. if (res && res[1]) {
  3604. this.current.once = Number(res[1]);
  3605. return;
  3606. }
  3607. }
  3608. if (typeof once === "number") {
  3609. this.current.once = once;
  3610. return;
  3611. }
  3612. }
  3613. window.fetchOnce().then((r) => {
  3614. this.current.once = r;
  3615. });
  3616. });
  3617. eventBus.on(CMD.REMOVE_TAG, async ({ username, tag }) => {
  3618. let oldTag = this.clone(this.tags);
  3619. let tags = this.tags[username] ?? [];
  3620. let rIndex = tags.findIndex((v) => v === tag);
  3621. if (rIndex > -1) {
  3622. tags.splice(rIndex, 1);
  3623. }
  3624. this.tags[username] = tags;
  3625. let res = await window.parse.saveTags(this.tags);
  3626. if (!res) {
  3627. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "标签删除失败!" });
  3628. this.tags = oldTag;
  3629. }
  3630. });
  3631. },
  3632. async getPostDetail(post, event) {
  3633. this.current = Object.assign({}, window.initPost, post);
  3634. this.current.read = this.readList[this.current.id] ?? { floor: 0, total: 0 };
  3635. this.show = true;
  3636. let url = window.baseUrl + "/t/" + post.id;
  3637. document.body.style.overflow = "hidden";
  3638. window.history.pushState({}, 0, post.href ?? url);
  3639. window.document.title = post.title ?? "V2EX";
  3640. let alreadyHasReply = this.current.replyList.length;
  3641. if (alreadyHasReply) {
  3642. this.$refs.postDetail.jumpLastRead(this.current.read.floor);
  3643. } else {
  3644. this.loading = true;
  3645. }
  3646. let apiRes = await window.fetch(url + "?p=1");
  3647. if (apiRes.status === 404) {
  3648. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "主题未找到" });
  3649. return this.loading = false;
  3650. }
  3651. if (apiRes.status === 403) {
  3652. this.loading = false;
  3653. this.show = false;
  3654. window.open(`https://www.v2ex.com/t/${post.id}?p=1&script=0`, "_black");
  3655. return;
  3656. }
  3657. if (apiRes.redirected) {
  3658. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "没有权限" });
  3659. return this.loading = false;
  3660. }
  3661. let htmlText = await apiRes.text();
  3662. let hasPermission = htmlText.search("你要查看的页面需要先登录(不可用)");
  3663. if (hasPermission > -1) {
  3664. eventBus.emit(CMD.SHOW_MSG, { type: "error", text: "你要查看的页面需要先登录(不可用)" });
  3665. return this.loading = false;
  3666. }
  3667. let bodyText = htmlText.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  3668. let body = $(bodyText[0]);
  3669. this.current = await window.parse.getPostDetail(this.current, body, htmlText);
  3670. if (this.current.replyList.length) {
  3671. let index2 = this.list.findIndex((v) => v.id == post.id);
  3672. if (index2 > -1) {
  3673. this.list[index2].replyList = this.current.replyList;
  3674. this.list[index2].nestedReplies = this.current.nestedReplies;
  3675. this.list[index2].once = this.current.once;
  3676. this.list[index2].createDate = this.current.createDate;
  3677. } else {
  3678. this.list.push(this.clone(this.current));
  3679. }
  3680. }
  3681. this.loading = false;
  3682. if (!alreadyHasReply) {
  3683. vue.nextTick(() => {
  3684. this.$refs.postDetail.jumpLastRead(this.current.read.floor);
  3685. });
  3686. }
  3687. console.log("当前帖子", this.current);
  3688. }
  3689. }
  3690. };
  3691. const _hoisted_1 = {
  3692. key: 0,
  3693. class: "nav flex flex-end"
  3694. };
  3695. const _hoisted_2 = {
  3696. key: 1,
  3697. class: "my-box flex f14 open-post",
  3698. style: { "margin": "2rem 0 0 0", "padding": "1rem" }
  3699. };
  3700. const _hoisted_3 = { class: "flex" };
  3701. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  3702. const _component_Setting = vue.resolveComponent("Setting");
  3703. const _component_TagModal = vue.resolveComponent("TagModal");
  3704. const _component_PostDetail = vue.resolveComponent("PostDetail");
  3705. const _component_Base64Tooltip = vue.resolveComponent("Base64Tooltip");
  3706. const _component_MsgModal = vue.resolveComponent("MsgModal");
  3707. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  3708. vue.createVNode(_component_Setting, {
  3709. modelValue: $data.config,
  3710. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.config = $event),
  3711. show: $data.configModal.show,
  3712. "onUpdate:show": _cache[1] || (_cache[1] = ($event) => $data.configModal.show = $event)
  3713. }, null, 8, ["modelValue", "show"]),
  3714. vue.createVNode(_component_TagModal, {
  3715. tags: $data.tags,
  3716. "onUpdate:tags": _cache[2] || (_cache[2] = ($event) => $data.tags = $event)
  3717. }, null, 8, ["tags"]),
  3718. vue.createVNode(_component_PostDetail, {
  3719. modelValue: $data.show,
  3720. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.show = $event),
  3721. ref: "postDetail",
  3722. displayType: $data.config.commentDisplayType,
  3723. "onUpdate:displayType": _cache[4] || (_cache[4] = ($event) => $data.config.commentDisplayType = $event),
  3724. onSaveReadList: $options.saveReadList,
  3725. loading: $data.loading
  3726. }, null, 8, ["modelValue", "displayType", "onSaveReadList", "loading"]),
  3727. vue.createVNode(_component_Base64Tooltip),
  3728. vue.createVNode(_component_MsgModal),
  3729. !$data.stopMe && $data.config.showToolbar ? (vue.openBlock(), vue.createElementBlock("div", {
  3730. key: 0,
  3731. class: vue.normalizeClass(["toolbar", [$data.isNight ? "isNight" : "", $data.config["viewType"]]])
  3732. }, [
  3733. $options.isList ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
  3734. vue.createElementVNode("div", {
  3735. class: vue.normalizeClass(["radio-group2", { isNight: $data.isNight }])
  3736. }, [
  3737. vue.createElementVNode("div", {
  3738. class: vue.normalizeClass(["radio", $data.config.viewType === "table" ? "active" : ""]),
  3739. onClick: _cache[5] || (_cache[5] = ($event) => $data.config.viewType = "table")
  3740. }, "表格 ", 2),
  3741. vue.createElementVNode("div", {
  3742. class: vue.normalizeClass(["radio", $data.config.viewType === "card" ? "active" : ""]),
  3743. onClick: _cache[6] || (_cache[6] = ($event) => $data.config.viewType = "card")
  3744. }, "卡片 ", 2)
  3745. ], 2)
  3746. ])) : vue.createCommentVNode("", true),
  3747. !$options.isList && !$data.show ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2, [
  3748. vue.createElementVNode("div", _hoisted_3, [
  3749. vue.createTextVNode(" 默认显示楼中楼 : "),
  3750. vue.createElementVNode("div", {
  3751. class: vue.normalizeClass(["switch light", { active: $data.config.autoOpenDetail }]),
  3752. onClick: _cache[7] || (_cache[7] = ($event) => $data.config.autoOpenDetail = !$data.config.autoOpenDetail)
  3753. }, null, 2)
  3754. ]),
  3755. vue.createElementVNode("div", {
  3756. class: vue.normalizeClass(["button light", { loading: $data.loading, isNight: $data.isNight }]),
  3757. onClick: _cache[8] || (_cache[8] = (...args) => $options.showPost && $options.showPost(...args))
  3758. }, " 点击显示楼中楼 ", 2)
  3759. ])) : vue.createCommentVNode("", true)
  3760. ], 2)) : vue.createCommentVNode("", true)
  3761. ], 64);
  3762. }
  3763. const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-f9a9d2e9"]]);
  3764. var _GM_notification = /* @__PURE__ */ (() => typeof GM_notification != "undefined" ? GM_notification : void 0)();
  3765. var _GM_openInTab = /* @__PURE__ */ (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)();
  3766. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  3767. let $section = document.createElement("section");
  3768. $section.id = "app";
  3769. function run() {
  3770. window.baseUrl = location.origin;
  3771. window.initPost = {
  3772. allReplyUsers: [],
  3773. content_rendered: "",
  3774. createDate: "",
  3775. fr: "",
  3776. replyList: [],
  3777. nestedReplies: [],
  3778. username: "",
  3779. member: {},
  3780. node: {},
  3781. headerTemplate: "",
  3782. title: "",
  3783. id: "",
  3784. type: "post",
  3785. once: "",
  3786. replyCount: 0,
  3787. clickCount: 0,
  3788. thankCount: 0,
  3789. collectCount: 0,
  3790. lastReadFloor: 0,
  3791. isFavorite: false,
  3792. isIgnore: false,
  3793. isThanked: false,
  3794. isReport: false
  3795. };
  3796. window.win = function() {
  3797. return window;
  3798. };
  3799. window.win().doc = window.win().document;
  3800. window.win().query = (v) => window.win().document.querySelector(v);
  3801. window.query = (v) => window.win().document.querySelector(v);
  3802. window.clone = (val) => JSON.parse(JSON.stringify(val));
  3803. window.user = {
  3804. tagPrefix: "--用户标签--",
  3805. tags: {},
  3806. tagsId: "",
  3807. username: "",
  3808. avatar: "",
  3809. readPrefix: "--已读楼层--",
  3810. readNoteItemId: "",
  3811. readList: {}
  3812. };
  3813. window.pageType = void 0;
  3814. window.pageData = { pageNo: 1 };
  3815. window.config = {
  3816. showToolbar: true,
  3817. showPreviewBtn: true,
  3818. autoOpenDetail: true,
  3819. openTag: true,
  3820. //给用户打标签
  3821. clickPostItemOpenDetail: true,
  3822. closePostDetailBySpace: true,
  3823. //点击空白处关闭详情
  3824. contentAutoCollapse: true,
  3825. //正文超长自动折叠
  3826. viewType: "table",
  3827. commentDisplayType: 0,
  3828. newTabOpen: false,
  3829. //新标签打开
  3830. base64: true,
  3831. //base功能
  3832. sov2ex: false,
  3833. postWidth: "",
  3834. showTopReply: true,
  3835. topReplyLoveMinCount: 3,
  3836. topReplyCount: 3,
  3837. autoJumpLastReadFloor: false,
  3838. rememberLastReadFloor: true,
  3839. autoSignin: true,
  3840. customBgColor: "",
  3841. version: 1,
  3842. collectBrowserNotice: false
  3843. };
  3844. window.isNight = $(".Night").length === 1;
  3845. window.cb = null;
  3846. window.postList = [];
  3847. window.parse = {
  3848. //解析帖子内容
  3849. async parsePostContent(post, body, htmlText) {
  3850. let once = htmlText.match(/var once = "([\d]+)";/);
  3851. if (once && once[1]) {
  3852. post.once = once[1];
  3853. }
  3854. post.isReport = htmlText.includes("你已对本主题进行了报告");
  3855. if (!post.title || !post.content_rendered) {
  3856. let main = body.find("#Main");
  3857. let aName = main.find(".header small.gray a:nth-child(1)");
  3858. if (aName) {
  3859. post.member.username = aName[0].innerText;
  3860. }
  3861. }
  3862. let topic_buttons = body.find(".topic_buttons");
  3863. if (topic_buttons.length) {
  3864. let favoriteNode = topic_buttons.find(".tb:first");
  3865. if (favoriteNode.length) {
  3866. post.isFavorite = favoriteNode[0].innerText === "取消收藏";
  3867. }
  3868. let ignoreNode = topic_buttons.find(".tb:nth-child(3)");
  3869. if (ignoreNode.length) {
  3870. post.isIgnore = ignoreNode[0].innerText === "取消忽略";
  3871. }
  3872. let thankNode = topic_buttons.find("#topic_thank .tb");
  3873. if (!thankNode.length) {
  3874. post.isThanked = true;
  3875. }
  3876. let topic_stats = topic_buttons.find(".topic_stats");
  3877. if (topic_stats.length) {
  3878. let text = topic_stats[0].innerText;
  3879. let reg1 = text.matchAll(/([\d]+)[\s]*人收藏/g);
  3880. let collectCountReg = [...reg1];
  3881. if (collectCountReg.length) {
  3882. post.collectCount = Number(collectCountReg[0][1]);
  3883. }
  3884. reg1 = text.matchAll(/([\d]+)[\s]*likes/g);
  3885. collectCountReg = [...reg1];
  3886. if (collectCountReg.length) {
  3887. post.collectCount = Number(collectCountReg[0][1]);
  3888. }
  3889. let reg2 = text.matchAll(/([\d]+)[\s]*人感谢/g);
  3890. let thankCountReg = [...reg2];
  3891. if (thankCountReg.length) {
  3892. post.thankCount = Number(thankCountReg[0][1]);
  3893. }
  3894. let reg3 = text.matchAll(/([\d]+)[\s]*次点击/g);
  3895. let clickCountReg = [...reg3];
  3896. if (clickCountReg.length) {
  3897. post.clickCount = Number(clickCountReg[0][1]);
  3898. }
  3899. reg3 = text.matchAll(/([\d]+)[\s]*views/g);
  3900. clickCountReg = [...reg3];
  3901. if (clickCountReg.length) {
  3902. post.clickCount = Number(clickCountReg[0][1]);
  3903. }
  3904. }
  3905. }
  3906. let header = body.find("#Main .box").first();
  3907. let temp = header.clone();
  3908. temp.find(".topic_buttons").remove();
  3909. let html = temp.html();
  3910. html = this.checkPhotoLink2Img(html);
  3911. post.headerTemplate = html;
  3912. return post;
  3913. },
  3914. //获取帖子所有回复
  3915. async getPostAllReplies(post, body, htmlText, pageNo = 1) {
  3916. var _a, _b;
  3917. if (body.find("#no-comments-yet").length) {
  3918. return post;
  3919. }
  3920. let box = body.find("#Main > .box")[1];
  3921. let cells = box.querySelectorAll(".cell");
  3922. if (cells && cells.length) {
  3923. post.fr = cells[0].querySelector(".cell .fr").innerHTML;
  3924. cells = Array.from(cells);
  3925. }
  3926. let snow = cells[0].querySelector(".snow");
  3927. post.createDate = ((_b = (_a = snow == null ? void 0 : snow.nextSibling) == null ? void 0 : _a.nodeValue) == null ? void 0 : _b.trim()) || "";
  3928. let repliesMap = [];
  3929. if (cells[1].id) {
  3930. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(1)) });
  3931. let replyList = this.getAllReply(repliesMap);
  3932. post.replyList = replyList;
  3933. post.replyCount = replyList.length;
  3934. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  3935. let nestedList = this.createNestedList(replyList, post.allReplyUsers);
  3936. if (nestedList)
  3937. post.nestedReplies = nestedList;
  3938. return post;
  3939. } else {
  3940. let promiseList = [];
  3941. return new Promise((resolve, reject) => {
  3942. repliesMap.push({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  3943. let pages = cells[1].querySelectorAll("a");
  3944. pages = Array.from(pages);
  3945. let url = window.baseUrl + "/t/" + post.id;
  3946. for (let i = 0; i < pages.length; i++) {
  3947. let currentPageNo = Number(pages[i].innerText);
  3948. if (currentPageNo == pageNo)
  3949. continue;
  3950. promiseList.push(this.fetchPostOtherPageReplies(url + "?p=" + currentPageNo, currentPageNo));
  3951. }
  3952. Promise.allSettled(promiseList).then(
  3953. (results) => {
  3954. results.filter((result) => result.status === "fulfilled").map((v) => repliesMap.push(v.value));
  3955. let replyList = this.getAllReply(repliesMap);
  3956. post.replyList = replyList;
  3957. post.replyCount = replyList.length;
  3958. post.allReplyUsers = Array.from(new Set(replyList.map((v) => v.username)));
  3959. let nestedList = this.createNestedList(replyList, post.allReplyUsers);
  3960. if (nestedList)
  3961. post.nestedReplies = nestedList;
  3962. resolve(post);
  3963. }
  3964. );
  3965. });
  3966. }
  3967. },
  3968. //请求帖子其他页的回复
  3969. fetchPostOtherPageReplies(href, pageNo) {
  3970. return new Promise((resolve) => {
  3971. $.get(href).then((res) => {
  3972. let s = res.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  3973. let box = $(s[0]).find("#Main .box")[1];
  3974. let cells = box.querySelectorAll(".cell");
  3975. cells = Array.from(cells);
  3976. resolve({ i: pageNo, replyList: this.parsePageReplies(cells.slice(2, cells.length - 1)) });
  3977. }).catch((r) => {
  3978. if (r.status === 403) {
  3979. cbChecker({ type: "restorePost", value: null });
  3980. }
  3981. });
  3982. });
  3983. },
  3984. //解析页面的回复
  3985. parsePageReplies(nodes) {
  3986. let replyList = [];
  3987. nodes.forEach((node, index2) => {
  3988. if (!node.id)
  3989. return;
  3990. let item = {
  3991. level: 0,
  3992. thankCount: 0,
  3993. isThanked: false,
  3994. isOp: false,
  3995. id: node.id.replace("r_", "")
  3996. };
  3997. let reply_content = node.querySelector(".reply_content");
  3998. item.reply_content = this.checkPhotoLink2Img(reply_content.innerHTML);
  3999. item.reply_text = reply_content.textContent;
  4000. let { users, floor } = this.parseReplyContent(item.reply_content);
  4001. item.replyUsers = users;
  4002. item.replyFloor = floor;
  4003. let ago = node.querySelector(".ago");
  4004. item.date = ago.textContent;
  4005. let userNode = node.querySelector("strong a");
  4006. item.username = userNode.textContent;
  4007. let avatar = node.querySelector("td img");
  4008. item.avatar = avatar.src;
  4009. let no = node.querySelector(".no");
  4010. item.floor = Number(no.textContent);
  4011. let thank_area = node.querySelector(".thank_area");
  4012. if (thank_area) {
  4013. item.isThanked = thank_area.classList.contains("thanked");
  4014. }
  4015. let small = node.querySelector(".small");
  4016. if (small) {
  4017. item.thankCount = Number(small.textContent);
  4018. }
  4019. let op = node.querySelector(".op");
  4020. if (op) {
  4021. item.isOp = true;
  4022. }
  4023. let mod = node.querySelector(".mod");
  4024. if (mod) {
  4025. item.isMod = true;
  4026. }
  4027. replyList.push(item);
  4028. });
  4029. return replyList;
  4030. },
  4031. //解析回复内容,解析出@用户,回复楼层。用于后续生成嵌套楼层
  4032. parseReplyContent(str) {
  4033. if (!str)
  4034. return;
  4035. let users = [];
  4036. let getUsername = (userStr) => {
  4037. let endIndex = userStr.indexOf('">');
  4038. if (endIndex > -1) {
  4039. let user = userStr.substring(0, endIndex);
  4040. if (!users.find((i) => i === user)) {
  4041. users.push(user);
  4042. }
  4043. }
  4044. };
  4045. let userReg = /@<a href="\/member\/([\s\S]+?)<\/a>/g;
  4046. let has = str.matchAll(userReg);
  4047. let res2 = [...has];
  4048. if (res2.length > 1) {
  4049. res2.map((item) => {
  4050. getUsername(item[1]);
  4051. });
  4052. }
  4053. if (res2.length === 1) {
  4054. getUsername(res2[0][1]);
  4055. }
  4056. let floor = -1;
  4057. if (users.length === 1) {
  4058. let floorReg = /@<a href="\/member\/[\s\S]+?<\/a>[\s]+#([\d]+)/g;
  4059. let hasFloor = str.matchAll(floorReg);
  4060. let res = [...hasFloor];
  4061. if (res.length) {
  4062. floor = Number(res[0][1]);
  4063. }
  4064. }
  4065. return { users, floor };
  4066. },
  4067. //获取帖子详情
  4068. async getPostDetail(post, body, htmlText, pageNo = 1) {
  4069. post = await this.parsePostContent(post, body, htmlText);
  4070. return await this.getPostAllReplies(post, body, htmlText, pageNo);
  4071. },
  4072. getAllReply(repliesMap = []) {
  4073. return repliesMap.sort((a, b) => a.i - b.i).reduce((pre, i) => {
  4074. pre = pre.concat(i.replyList);
  4075. return pre;
  4076. }, []);
  4077. },
  4078. //生成嵌套回复
  4079. createNestedList(allList = []) {
  4080. if (!allList.length)
  4081. return [];
  4082. if (Date.now() - window.win().lastCallDate < 1e3) {
  4083. return false;
  4084. }
  4085. let list = window.clone(allList);
  4086. let nestedList = [];
  4087. list.map((item, index2) => {
  4088. let startList = list.slice(0, index2);
  4089. let startReplyUsers = Array.from(new Set(startList.map((v) => v.username)));
  4090. let endList = list.slice(index2 + 1);
  4091. if (index2 === 0) {
  4092. nestedList.push(this.findChildren(item, endList, list));
  4093. } else {
  4094. if (!item.isUse) {
  4095. let isOneLevelReply = false;
  4096. if (item.replyUsers.length) {
  4097. if (item.replyUsers.length > 1) {
  4098. isOneLevelReply = true;
  4099. } else {
  4100. isOneLevelReply = !startReplyUsers.find((v) => v === item.replyUsers[0]);
  4101. }
  4102. } else {
  4103. isOneLevelReply = true;
  4104. }
  4105. if (isOneLevelReply) {
  4106. item.level === 0;
  4107. nestedList.push(this.findChildren(item, endList, list));
  4108. }
  4109. }
  4110. }
  4111. });
  4112. window.win().lastCallDate = Date.now();
  4113. return nestedList;
  4114. },
  4115. //查找子回复
  4116. findChildren(item, endList, all) {
  4117. var _a;
  4118. const fn = (child, endList2, parent) => {
  4119. child.level = parent.level + 1;
  4120. let rIndex = all.findIndex((v) => v.floor === child.floor);
  4121. if (rIndex > -1) {
  4122. all[rIndex].isUse = true;
  4123. }
  4124. parent.children.push(this.findChildren(child, endList2, all));
  4125. };
  4126. item.children = [];
  4127. let floorReplyList = [];
  4128. for (let i = 0; i < endList.length; i++) {
  4129. let currentItem = endList[i];
  4130. if (currentItem.isUse)
  4131. continue;
  4132. if (currentItem.replyFloor === item.floor) {
  4133. if (currentItem.replyUsers.length === 1 && currentItem.replyUsers[0] === item.username) {
  4134. currentItem.isUse = true;
  4135. floorReplyList.push({ endList: endList.slice(i + 1), currentItem });
  4136. } else {
  4137. currentItem.isWrong = true;
  4138. }
  4139. }
  4140. }
  4141. floorReplyList.reverse().map(({ currentItem, endList: endList2 }) => {
  4142. fn(currentItem, endList2, item);
  4143. });
  4144. let nextMeIndex = endList.findIndex((v) => {
  4145. var _a2;
  4146. return v.username === item.username && ((_a2 = v.replyUsers) == null ? void 0 : _a2[0]) !== item.username;
  4147. });
  4148. let findList = nextMeIndex > -1 ? endList.slice(0, nextMeIndex) : endList;
  4149. for (let i = 0; i < findList.length; i++) {
  4150. let currentItem = findList[i];
  4151. if (currentItem.isUse)
  4152. continue;
  4153. if (currentItem.replyUsers.length === 1) {
  4154. if (currentItem.replyFloor !== -1) {
  4155. if (((_a = all[currentItem.replyFloor - 1]) == null ? void 0 : _a.username) === currentItem.replyUsers[0]) {
  4156. continue;
  4157. }
  4158. }
  4159. let endList2 = endList.slice(i + 1);
  4160. if (currentItem.username === item.username) {
  4161. if (currentItem.replyUsers[0] === item.username) {
  4162. fn(currentItem, endList2, item);
  4163. }
  4164. break;
  4165. } else {
  4166. if (currentItem.replyUsers[0] === item.username) {
  4167. fn(currentItem, endList2, item);
  4168. }
  4169. }
  4170. } else {
  4171. if (currentItem.username === item.username)
  4172. break;
  4173. }
  4174. }
  4175. item.children = item.children.sort((a, b) => a.floor - b.floor);
  4176. return item;
  4177. },
  4178. //解析页面帖子列表
  4179. parsePagePostList(list, box) {
  4180. list.forEach((itemDom) => {
  4181. let item = window.clone(window.initPost);
  4182. let item_title = itemDom.querySelector(".item_title a");
  4183. let { href, id } = window.parse.parseA(item_title);
  4184. item.id = id;
  4185. item.href = href;
  4186. item.url = location.origin + "/api/topics/show.json?id=" + item.id;
  4187. itemDom.classList.add("post-item");
  4188. itemDom.classList.add(`id_${id}`);
  4189. itemDom.dataset["href"] = href;
  4190. itemDom.dataset["id"] = id;
  4191. window.postList.push(item);
  4192. });
  4193. Promise.allSettled(window.postList.map((item) => $.get(item.url))).then((res) => {
  4194. let ok = res.filter((r) => r.status === "fulfilled").map((v) => v.value[0]);
  4195. box.style.boxShadow = "unset";
  4196. box.style.background = "unset";
  4197. if (window.config.viewType === "card") {
  4198. list.forEach((itemDom) => itemDom.classList.add("preview"));
  4199. }
  4200. ok.map((postItem) => {
  4201. if (postItem == null ? void 0 : postItem.id) {
  4202. let itemDom = box.querySelector(`.id_${postItem.id}`);
  4203. if (window.config.showPreviewBtn) {
  4204. let td = itemDom.querySelector("td:nth-child(4)");
  4205. td.style.position = "relative";
  4206. let toggle = document.createElement("div");
  4207. toggle.dataset["id"] = postItem.id;
  4208. toggle.classList.add("toggle");
  4209. toggle.innerText = "点击展开/收起";
  4210. td.append(toggle);
  4211. }
  4212. let index2 = window.postList.findIndex((v) => v.id == postItem.id);
  4213. if (index2 > -1) {
  4214. let obj = window.postList[index2];
  4215. window.postList[index2] = Object.assign({}, obj, postItem);
  4216. if (postItem.content_rendered) {
  4217. let a = document.createElement("a");
  4218. a.href = obj.href;
  4219. a.classList.add("post-content");
  4220. let div = document.createElement("div");
  4221. div.innerHTML = postItem.content_rendered;
  4222. a.append(div);
  4223. itemDom.append(a);
  4224. }
  4225. }
  4226. }
  4227. });
  4228. cbChecker({ type: "syncData" });
  4229. });
  4230. },
  4231. parseA(a) {
  4232. let href = a.href;
  4233. let id;
  4234. if (href.includes("/t/")) {
  4235. id = href.substring(href.indexOf("/t/") + 3, href.indexOf("/t/") + 9);
  4236. }
  4237. return { href, id, title: a.innerText };
  4238. },
  4239. //创建记事本子条目
  4240. async createNoteItem(itemName) {
  4241. return new Promise(async (resolve) => {
  4242. let data = new FormData();
  4243. data.append("content", itemName);
  4244. data.append("parent_id", 0);
  4245. data.append("syntax", 0);
  4246. let apiRes = await window.win().fetch(`${window.baseUrl}/notes/new`, { method: "post", body: data });
  4247. console.log(apiRes);
  4248. if (apiRes.redirected && apiRes.status === 200) {
  4249. resolve(apiRes.url.substr(-5));
  4250. return;
  4251. }
  4252. resolve(null);
  4253. });
  4254. },
  4255. //编辑记事本子条目
  4256. async editNoteItem(val, id) {
  4257. let data = new FormData();
  4258. data.append("content", val);
  4259. data.append("syntax", 0);
  4260. let apiRes = await window.fetch(`${window.baseUrl}/notes/edit/${id}`, {
  4261. method: "post",
  4262. body: data
  4263. });
  4264. return apiRes.redirected && apiRes.status === 200;
  4265. },
  4266. //标签操作
  4267. async saveTags(val) {
  4268. return await this.editNoteItem(window.user.tagPrefix + JSON.stringify(val), window.user.tagsId);
  4269. },
  4270. //已读楼层操作
  4271. async saveReadList(val) {
  4272. return await this.editNoteItem(window.user.readPrefix + JSON.stringify(val), window.user.readNoteItemId);
  4273. },
  4274. //图片链接转Img标签
  4275. checkPhotoLink2Img(str) {
  4276. if (!str)
  4277. return;
  4278. try {
  4279. let imgWebs = [
  4280. /<a((?!<a).)*href="https?:\/\/((?!<a).)*imgur.com((?!<a).)*>(((?!<a).)*)<\/a>/g,
  4281. /<a((?!<a).)*href="https?:\/\/((?!<a).)*\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)((?!<a).)*>(((?!<a).)*)<\/a>/g
  4282. ];
  4283. imgWebs.map((v, i) => {
  4284. let has = str.matchAll(v);
  4285. let res2 = [...has];
  4286. res2.map((r) => {
  4287. let p = i === 0 ? r[4] : r[5];
  4288. if (p) {
  4289. let link = p.toLowerCase();
  4290. let src = p;
  4291. if (link.includes(".png") || link.includes(".jpg") || link.includes(".jpeg") || link.includes(".gif")) {
  4292. } else {
  4293. src = p + ".png";
  4294. }
  4295. str = str.replace(r[0], `<img src="${src}" data-originUrl="${p}" data-notice="这个img标签由v2ex-超级增强脚本解析" style="max-width: 100%">`);
  4296. }
  4297. });
  4298. });
  4299. } catch (e) {
  4300. console.log("正则解析html里面的a标签的图片链接出错了");
  4301. }
  4302. return str;
  4303. }
  4304. };
  4305. async function sleep(time) {
  4306. return new Promise((resolve) => {
  4307. setTimeout(resolve, time);
  4308. });
  4309. }
  4310. async function cbChecker(val, count = 0) {
  4311. if (window.cb) {
  4312. window.cb(val);
  4313. } else {
  4314. while (!window.cb && count < 20) {
  4315. await sleep(500);
  4316. count++;
  4317. }
  4318. window.cb && window.cb(val);
  4319. }
  4320. }
  4321. function feedback() {
  4322. _GM_openInTab("https://github.com/zyronon/v2ex-script/discussions/", {
  4323. active: true,
  4324. insert: true,
  4325. setParent: true
  4326. });
  4327. }
  4328. function initMonkeyMenu() {
  4329. try {
  4330. _GM_registerMenuCommand("脚本设置", function(event) {
  4331. cbChecker({ type: "openSetting" });
  4332. });
  4333. _GM_registerMenuCommand("💬 反馈 & 建议", feedback);
  4334. } catch (e) {
  4335. console.error("无法使用Tampermonkey");
  4336. }
  4337. }
  4338. function initStyle() {
  4339. let style2 = `
  4340. html, body {
  4341. font-size: 62.5%;
  4342. }
  4343.  
  4344. #Wrapper {
  4345. height: unset !important;
  4346. width: unset !important;
  4347. }
  4348.  
  4349. #Wrapper > .content {
  4350. height: unset !important;
  4351. width: unset !important;
  4352. }
  4353.  
  4354. .post-item {
  4355. background: white;
  4356. }
  4357.  
  4358. .post-item > .post-content {
  4359. height: 0;
  4360. margin-top: 0;
  4361. }
  4362.  
  4363. .post-item:hover .toggle {
  4364. display: flex;
  4365. }
  4366.  
  4367. .toggle {
  4368. position: absolute;
  4369. right: 0;
  4370. top: 0.5rem;
  4371. width: 9rem;
  4372. height: 100%;
  4373. display: flex;
  4374. justify-content: flex-end;
  4375. align-items: flex-end;
  4376. cursor: pointer;
  4377. font-size: 1.2rem;
  4378. color: #ccc;
  4379. display: none;
  4380. }
  4381.  
  4382. .preview {
  4383. margin: 1rem 0;
  4384. border: 1px solid #c8c8c8;
  4385. border-radius: 0.4rem;
  4386. cursor: pointer;
  4387. }
  4388.  
  4389. .preview:hover {
  4390. border: 1px solid #968b8b;
  4391. }
  4392.  
  4393. .preview > .post-content {
  4394. height: unset !important;
  4395. margin-top: 0.5rem !important;
  4396. }
  4397.  
  4398. .preview .topic-link:link {
  4399. color: black !important;
  4400. }
  4401.  
  4402. .post-content {
  4403. margin-top: 0.5rem;
  4404. display: block;
  4405. max-height: 20rem;
  4406. overflow: hidden;
  4407. text-decoration: unset !important;
  4408. line-break: anywhere;
  4409. -webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);
  4410. }
  4411.  
  4412. .post-content:link {
  4413. color: #494949;
  4414. }
  4415.  
  4416.  
  4417. .post-content:visited {
  4418. color: #afb9c1 !important;
  4419. }
  4420.  
  4421. .Night .post-item {
  4422. background: #18222d !important;
  4423. }
  4424.  
  4425. .Night .preview {
  4426. border: 1px solid #3b536e;
  4427. }
  4428.  
  4429. .Night .preview > .post-content:link {
  4430. color: #d1d5d9;
  4431. }
  4432.  
  4433. .Night .preview > .post-content:visited {
  4434. color: #393f4e !important;
  4435. }
  4436.  
  4437. .Night .preview .topic-link:link {
  4438. color: #c0dbff !important;
  4439. }
  4440.  
  4441. `;
  4442. let addStyle2 = document.createElement("style");
  4443. addStyle2.rel = "stylesheet";
  4444. addStyle2.type = "text/css";
  4445. addStyle2.innerHTML = style2;
  4446. $(window.win().doc.head).append(addStyle2);
  4447. }
  4448. function qianDao() {
  4449. let timeNow = (/* @__PURE__ */ new Date()).getUTCFullYear() + "/" + ((/* @__PURE__ */ new Date()).getUTCMonth() + 1) + "/" + (/* @__PURE__ */ new Date()).getUTCDate();
  4450. if (window.pageType === PageType.Home) {
  4451. let qiandao = window.query('.box .inner a[href="/mission/daily"]');
  4452. if (qiandao) {
  4453. qianDao_(qiandao, timeNow);
  4454. } else if (window.win().doc.getElementById("gift_v2excellent")) {
  4455. window.win().doc.getElementById("gift_v2excellent").click();
  4456. localStorage.setItem("menu_clockInTime", timeNow);
  4457. console.info("[V2EX - 超级增强] 自动签到完成!");
  4458. } else {
  4459. console.info("[V2EX - 超级增强] 自动签到完成!");
  4460. }
  4461. } else {
  4462. let timeOld = localStorage.getItem("menu_clockInTime");
  4463. if (!timeOld || timeOld != timeNow) {
  4464. qianDaoStatus_(timeNow);
  4465. } else {
  4466. console.info("[V2EX - 超级增强] 自动签到完成!");
  4467. }
  4468. }
  4469. }
  4470. function qianDao_(qiandao, timeNow) {
  4471. let url = window.baseUrl + "/mission/daily/redeem?" + RegExp("once\\=(\\d+)").exec(document.querySelector("div#Top .tools, #menu-body").innerHTML)[0];
  4472. console.log("url", url);
  4473. $.get(url).then((r) => {
  4474. let bodyText = r.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  4475. let html = $(bodyText[0]);
  4476. if (html.find("li.fa.fa-ok-sign").length) {
  4477. html = html.find("#Main").text().match(/已连续登录(不可用) (\d+?) 天/)[0];
  4478. localStorage.setItem("menu_clockInTime", timeNow);
  4479. console.info("[V2EX - 超级增强] 自动签到完成!");
  4480. if (qiandao) {
  4481. qiandao.textContent = `自动签到完成!${html}`;
  4482. qiandao.href = "javascript:void(0);";
  4483. }
  4484. } else {
  4485. _GM_notification({
  4486. text: "自动签到失败!请访问 V2EX 首页试试。\n如果连续几天都签到失败,请联系作者解决!",
  4487. timeout: 4e3,
  4488. onclick() {
  4489. feedback();
  4490. }
  4491. });
  4492. console.warn("[V2EX 增强] 自动签到失败!请访问 V2EX 首页试试。如果连续几天都签到失败,请联系作者解决!");
  4493. if (qiandao)
  4494. qiandao.textContent = "自动签到失败!请尝试手动签到!";
  4495. }
  4496. });
  4497. }
  4498. function qianDaoStatus_(timeNow) {
  4499. $.get(window.baseUrl + "/mission/daily").then((r) => {
  4500. let bodyText = r.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  4501. let html = $(bodyText[0]);
  4502. if (html.find('input[value^="领取"]').length) {
  4503. qianDao_(null, timeNow);
  4504. } else {
  4505. console.info("[V2EX 增强] 已经签过到了。");
  4506. localStorage.setItem("menu_clockInTime", timeNow);
  4507. }
  4508. });
  4509. }
  4510. function checkPageType() {
  4511. let location2 = window.win().location;
  4512. if (location2.pathname === "/") {
  4513. window.pageType = PageType.Home;
  4514. } else if (location2.href.match(/.com\/?tab=/)) {
  4515. window.pageType = PageType.Home;
  4516. } else if (location2.href.match(/.com\/go\//)) {
  4517. if (!location2.href.includes("/links")) {
  4518. window.pageType = PageType.Node;
  4519. }
  4520. } else if (location2.href.match(/.com\/recent/)) {
  4521. window.pageType = PageType.Home;
  4522. } else {
  4523. let r = location2.href.match(/.com\/t\/([\d]+)/);
  4524. if (r) {
  4525. window.pageType = PageType.Post;
  4526. window.pageData.id = r[1];
  4527. if (location2.search) {
  4528. let pr = location2.href.match(/\?p=([\d]+)/);
  4529. if (pr)
  4530. window.pageData.pageNo = Number(pr[1]);
  4531. }
  4532. }
  4533. }
  4534. }
  4535. function getNoteItemContent(id, prefix) {
  4536. return new Promise((resolve, reject) => {
  4537. $.get(window.baseUrl + "/notes/edit/" + id).then((r2) => {
  4538. let bodyText = r2.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  4539. let body = $(bodyText[0]);
  4540. let text = body.find(".note_editor").text();
  4541. if (text === prefix) {
  4542. resolve({});
  4543. } else {
  4544. let tagJson = text.substring(prefix.length);
  4545. try {
  4546. resolve(JSON.parse(tagJson));
  4547. } catch (e) {
  4548. console.log("tage", tagJson);
  4549. resolve({});
  4550. }
  4551. }
  4552. });
  4553. });
  4554. }
  4555. async function initNoteData() {
  4556. $.get(window.baseUrl + "/notes").then(async (r) => {
  4557. let bodyText = r.match(/<body[^>]*>([\s\S]+?)<\/body>/g);
  4558. let body = $(bodyText[0]);
  4559. let items = body.find("#Main .box .note_item_title a");
  4560. if (items.length) {
  4561. let tagItem = Array.from(items).find((v) => v.innerText.includes(window.user.tagPrefix));
  4562. if (tagItem) {
  4563. window.user.tagsId = tagItem.href.substr(-5);
  4564. window.user.tags = await getNoteItemContent(window.user.tagsId, window.user.tagPrefix);
  4565. } else {
  4566. let r2 = await window.parse.createNoteItem(window.user.tagPrefix);
  4567. r2 && (window.user.tagsId = r2);
  4568. }
  4569. let readItem = Array.from(items).find((v) => v.innerText.includes(window.user.readPrefix));
  4570. if (readItem) {
  4571. window.user.readNoteItemId = readItem.href.substr(-5);
  4572. window.user.readList = await getNoteItemContent(window.user.readNoteItemId, window.user.readPrefix);
  4573. } else {
  4574. let r2 = await window.parse.createNoteItem(window.user.readPrefix);
  4575. r2 && (window.user.readNoteItemId = r2);
  4576. }
  4577. cbChecker({ type: "syncData" });
  4578. }
  4579. });
  4580. }
  4581. function initConfig() {
  4582. return new Promise((resolve) => {
  4583. let configStr = window.win().localStorage.getItem("v2ex-config");
  4584. if (configStr) {
  4585. let configObj = JSON.parse(configStr);
  4586. configObj = configObj[window.user.username ?? "default"];
  4587. if (configObj) {
  4588. window.config = Object.assign(window.config, configObj);
  4589. }
  4590. }
  4591. resolve(window.config);
  4592. });
  4593. }
  4594. function initSoV2ex() {
  4595. var $search = $("#search");
  4596. var searchEvents = $._data($search[0], "events");
  4597. console.log($search, searchEvents);
  4598. var oKeydownEvent = searchEvents["keydown"][0]["handler"];
  4599. var oInputEvent = searchEvents["input"][0]["handler"];
  4600. $search.attr("placeholder", "sov2ex");
  4601. $search.unbind("keydown", oKeydownEvent);
  4602. $search.unbind("input", oInputEvent);
  4603. $search.on("input", function(e) {
  4604. oInputEvent(e);
  4605. $(".search-item:last").attr("href", "https://www.sov2ex.com/?q=" + $search.val()).text("sov2ex " + $search.val());
  4606. });
  4607. $search.keydown(function(e) {
  4608. if (e.code == "Enter" || e.code == "NumpadEnter" || e.keyCode === 13) {
  4609. if ($(".search-item:last").is(".active")) {
  4610. $(this).val($(this).val().replace(/[#%&]/g, ""));
  4611. window.open("https://www.sov2ex.com/?q=" + $(this).val());
  4612. return 0;
  4613. }
  4614. }
  4615. oKeydownEvent(e);
  4616. });
  4617. }
  4618. function addSettingText() {
  4619. let setting = $(`<a href="javascript:void 0;" class="top">脚本设置</a>`);
  4620. setting.on("click", () => {
  4621. cbChecker({ type: "openSetting" });
  4622. });
  4623. $(".tools").prepend(setting);
  4624. }
  4625. function initCustomBgColor() {
  4626. let style2 = `#Wrapper {
  4627. background-color: ${window.config.customBgColor} !important;
  4628. background-image: unset !important;
  4629. }`;
  4630. let addStyle2 = document.createElement("style");
  4631. addStyle2.rel = "stylesheet";
  4632. addStyle2.type = "text/css";
  4633. addStyle2.innerHTML = style2;
  4634. $(window.win().doc.head).append(addStyle2);
  4635. }
  4636. function init() {
  4637. checkPageType();
  4638. initMonkeyMenu();
  4639. initStyle();
  4640. let top2 = document.querySelector(".tools .top:nth-child(2)");
  4641. if (top2 && top2.textContent !== "注册(不可用)") {
  4642. window.user.username = top2.textContent;
  4643. window.user.avatar = $("#Rightbar .box .avatar").attr("src");
  4644. initNoteData();
  4645. }
  4646. addSettingText();
  4647. initConfig().then((r) => {
  4648. if (window.config.sov2ex) {
  4649. setTimeout(initSoV2ex, 1e3);
  4650. }
  4651. if (window.config.customBgColor) {
  4652. initCustomBgColor();
  4653. }
  4654. try {
  4655. if (window.config.autoSignin && window.user.username) {
  4656. qianDao();
  4657. }
  4658. } catch (e) {
  4659. console.log("签到失败");
  4660. }
  4661. });
  4662. let box;
  4663. let list;
  4664. switch (window.pageType) {
  4665. case PageType.Node:
  4666. box = window.win().doc.querySelectorAll("#Wrapper #Main .box");
  4667. let topics = box[1].querySelector("#TopicsNode");
  4668. list = topics.querySelectorAll(".cell");
  4669. list[0].before($section);
  4670. window.parse.parsePagePostList(list, box[1]);
  4671. break;
  4672. case PageType.Home:
  4673. box = document.querySelector("#Wrapper #Main .box");
  4674. list = box.querySelectorAll(".item");
  4675. list[0].before($section);
  4676. window.parse.parsePagePostList(list, box);
  4677. break;
  4678. case PageType.Post:
  4679. if (window.config.postWidth) {
  4680. let Main = $("#Main");
  4681. Main.css({
  4682. "width": window.config.postWidth,
  4683. margin: "unset"
  4684. });
  4685. $("#Wrapper > .content").css({
  4686. "max-width": "unset",
  4687. display: "flex",
  4688. "justify-content": "center",
  4689. gap: "20px"
  4690. });
  4691. Main.after($("#Rightbar"));
  4692. }
  4693. box = document.querySelector("#Wrapper #Main .box");
  4694. box.after($section);
  4695. let post = Object.assign({}, window.clone(window.initPost), { id: window.pageData.id });
  4696. let body = $(window.win().doc.body);
  4697. let htmlText = window.win().doc.documentElement.outerHTML;
  4698. window.parse.parsePostContent(
  4699. post,
  4700. body,
  4701. htmlText
  4702. ).then(async (res) => {
  4703. await cbChecker({ type: "postContent", value: res }, 0);
  4704. });
  4705. window.parse.getPostAllReplies(
  4706. post,
  4707. body,
  4708. htmlText,
  4709. window.pageData.pageNo
  4710. ).then(async (res) => {
  4711. await cbChecker({ type: "postReplies", value: res }, 0);
  4712. });
  4713. break;
  4714. default:
  4715. console.error("未知页面");
  4716. break;
  4717. }
  4718. }
  4719. window.canParseV2exPage = !window.location.href.includes("script=0");
  4720. if (window.canParseV2exPage) {
  4721. init();
  4722. } else {
  4723. alert("脚本无法查看此主题,已为您单独打开此主题");
  4724. }
  4725. }
  4726. run();
  4727. let vueApp = vue.createApp(App);
  4728. vueApp.config.unwrapInjectedRef = true;
  4729. vueApp.mount($section);
  4730.  
  4731. })(Vue);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址