V2EX - 超级增强

让V2EX现代化。支持楼中楼、简洁模式、高赞回复排序、发送图片和表情、base64 解码等功能

目前为 2023-12-11 提交的版本。查看 最新版本

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

QingJ © 2025

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