// ==UserScript== // @name 高效探索 - 阿儿法营/稽木世界社区优化插件 // @namespace https://waterblock79.github.io/ // @version 0.2.0 // @description 提供优化、补丁及小功能提升社区内的探索效率和用户体验 // @author waterblock79 // @match http*://gitblock.cn/* // @match http*://aerfaying.com/* // @match http*://3eworld.cn/* // @icon https://www.google.com/s2/favicons?sz=64&domain=gitblock.cn // @grant none // @license MIT // @downloadURL none // ==/UserScript== (function() { const encodeHtml = Blockey.Utils.encodeHtml; // === 在 ajax 上挂载事件 === $.ajaxSettings.xhr = function pf(){ try{ let xhr = new XMLHttpRequest; xhr.onload = e => { if(JSON.parse(e.target.response).userMap != undefined){ let userMap = JSON.parse(e.target.response).userMap; Object.keys(userMap).forEach( key => window.userInfoCache[key] = userMap[key] ) } } return xhr; }catch(e){} }; // === 传入评论 ID,显示评论详尽信息 === window.showCommentInfo = (id) => { Blockey.Utils.ajax({ url:'/WebApi/Comment/GetPage', data: { forType: Blockey.Utils.getContext().targetType, forId: Blockey.Utils.getContext().target.id, pageIndex: 1, scrollToCommentId: id }, success: (data) => { data = data.scrollToThread.id == id ? data.scrollToThread : data.replies.filter( d => { return d.id == id } )[0] ; let linkToComment = (location.href.includes('#') ? location.href.split('#')[0] : location.href) + '#commentId=' + id; Blockey.Utils.confirm( "评论", ` 评论时间
${ ( new Date(data.createTime) ).toLocaleString() }

评论链接
${linkToComment}

${ data.content }
` ) } }) } // // === 评论 ID 显示 & 点击显示详细信息事件 === if( localStorage.getItem('explore:comment_id') == null ){ localStorage.setItem('explore:comment_id',1) } setInterval(()=>{ let comments = document.querySelectorAll('.comment_comment_P_hgY'); for( let i = 0; i < comments.length; i++ ) { comments[i].querySelector('.comment_time_3A6Cg').innerHTML += comments[i].querySelector('.comment_time_3A6Cg').innerHTML.includes('#') || localStorage.getItem('explore:comment_id') == 0 || comments[i].id == '' ? `` : ` #${comments[i].id} ` } },1000) document.querySelector('.menu-bar_topnav_3HgyJ').style.zIndex = 999999999 // // === 用户信息显示 === if(location.pathname.match(/\/Users\/(\w+\/?)/g) != null) { // 若链接匹配 /Users/NUMBER/ 或 /Users/NUMBER // 轮询等待“加入时间”的元素被创建 let setUserInfo = setInterval ( () => { if(document.querySelector('.profile-head_join_HPHzg') != null) { // 请求用户邀请 API Blockey.Utils.ajax({ url: `/WebApi/Users/${Blockey.Utils.getContext().target.id}/GetPagedInvitedUsers`, data: { pageIndex: 1, pageSize: 60 }, success: (data) => { let length = data.invitorPath.length; // 如果这个人是被邀请的,那就在在“xxxx-xx-xx加入”后面加上邀请信息 document.querySelector('.profile-head_join_HPHzg').querySelector('small').innerHTML += length == 1 ? '' : ` · 由${ encodeHtml(data.invitorPath[length-2].username) }邀请`; } }) // 清掉这个轮询 clearInterval(setUserInfo); } }, 200); } // // === 修复作品“继续加载”的预览图尺寸问题 === let fixProjectImage = setInterval ( () => { if(document.querySelector('.img-responsive') != null) { document.querySelector('.img-responsive').style['width'] = '100%'; clearInterval(fixProjectImage); } }, 200); // // === 悬停在用户名链接上展示用户卡片 === if( localStorage.getItem('explore:user_box') == null ){ localStorage.setItem('explore:user_box',1) } ; let style = document.createElement('style'); style.innerHTML = '.comment_info_2Sjc0 { overflow: inherit !important } .' document.head.appendChild(style); ; window.userInfoCache = {}; let userBox = setInterval ( () => { // 真人认证等级、用户等级所对应的 class let humanVerifiedClass = { 1: "human-verified-icon_verifiedLevel-1_-X3x2", 2: "human-verified-icon_verifiedLevel-2_1Byk3", 3: "human-verified-icon_verifiedLevel-3_2hde9", 4: "human-verified-icon_verifiedLevel-4_2gbJU", 5: "human-verified-icon_verifiedLevel-5_2isZE", }, levelClass = (level) => { let classList = { "level-0": "user-level_level-0_3HviE", "level-1": "user-level_level-1_uTxh6", "level-2": "user-level_level-2_3b_PK", "level-3": "user-level_level-3_1Rr5c", "level-4": "user-level_level-4_18jcT", }; if(0 data.onmouseenter = (e)=>{ if( e.target.classList.contains('inBox') ) return; // 有时候加载比较满慢会同时出现俩用户框,于是我觉得可以让在创建新用户框的时候先检测一下,清除掉不是属于自己的、多余的用户框 document.querySelectorAll('.user_box').forEach( d => { if (data.id != d.id ) { d.remove() } } ) // 传入数据,在该用户名下生成一个用户简讯框 let addUserBox = (data, commentId) => { let dom = document.createElement('div'); dom.style = 'z-index: 797979;position: absolute;width: 75%;height: 7.5em;border: 1px #4c97ff solid;border-radius: 3px;background: white;display: flex;align-items: center;'; dom.classList.add('user_box'); dom.id = commentId; data.user = data; dom.innerHTML = ` ${ data.user.adminLevel > 0 && localStorage.getItem('explore:show-admin-badge') != 'disabled' ? `
` : `` }
${ encodeHtml(data.user.username) } Lv.${data.user.level} ${data.user.goldCoins} 金币 ${new Date(data.user.createTime).toLocaleDateString().replaceAll('/','-')} 加入
`; e.target.parentNode.appendChild(dom); }; // 从用户名的链接提取用户 ID let userId = Number(e.target.href.match(/[0-9]+/g)[0]); // 如果这个用户的信息没被存下,那就发送请求获取数据 if( window.userInfoCache[userId] == undefined ) { let cId = data.parentElement.parentElement.id; // 请求里面的 data 给代表这个链接元素的外面的 data 覆盖掉了...... $.ajax({ url: `/WebApi/Users/${e.target.href.match(/[0-9]+/g)[0]}/Get`, method: 'post', success: (data) => { addUserBox( data, cId ); // 存好这个用户的数据,下回就不再请求了 window.userInfoCache[userId] = data; } }); } else { addUserBox( window.userInfoCache[userId], data.parentElement.parentElement.id ) } } ) // 给每个评论的用户名加上“鼠标离开”的事件 document.querySelectorAll('a.comment_name_2ZnFZ').forEach( data => data.onmouseleave = data.classList.contains('inBox') ? null : ()=>{ document.querySelectorAll('.user_box').forEach( d => d.remove() ) } ); }, 300); // 若未开启用户简讯框功能,那就清除掉这个轮询 if( localStorage.getItem('explore:user_box') == 0 ) { clearInterval(userBox); } // // === 在菜单中插入插件设置 === // 植入开启插件设置的函数 window.openSetting = () => { Blockey.Utils.confirm('插件设置',` 主要功能
启用用户简讯框

全屏蓝色加载遮盖设置
不改变
以在左下角显示不影响浏览的加载中提示替代之
完全隐藏


小功能
启用评论 ID 显示
开源于 waterblock79/aerfaying-explore
`); } // 在用户下拉栏里植入打开插件设置的摁键 document.querySelector('.user-dropdown-menu_wrapper_3RsXx').insertBefore( document.createElement('li'), document.querySelector('#nav-settings') ).innerHTML = `插件设置`; // // === 转化全屏蓝色加载 === // explore:loading = 0: 不改变, 1: 隐藏并启用左下加载提示, 2: 完全隐藏 if( localStorage.getItem('explore:loading') == null ){ localStorage.setItem('explore:loading', 1) } // 如果 explore:loading 设置是 1 或 2 if( localStorage.getItem('explore:loading') >= 1 ) { var onLoading = false, onProjectLoading = false; // 把原先的加载遮盖的 Class 加上 Display: none 屏蔽掉 ; let style = document.createElement('style'); style.innerHTML = '.loader_background_1-Rwn { display: none !important }' document.head.appendChild(style); ; // 一个小工具,传入选择器,若元素存在便返回 true var elementExist = (dom) => { return document.querySelector(dom) != null ? true : false } // 当 explore:loading 设置为 1 便显示左下角加载提示 if( localStorage.getItem('explore:loading') == 1 ) { // 轮询检测原先全屏加载出现 setInterval(()=>{ // 检测全屏加载遮盖是否存在(用了 not 选择器来排除掉咱自己创建的那个作品加载遮盖) if(elementExist('.loader_background_1-Rwn:not(#explore-loading-project)')){ // 如果 onLoading 还没被设为 true,那说明还没添加左下角加载提示,就加上先 if(onLoading == false){ // 隐藏原先全屏加载遮盖 document.querySelector('.loader_background_1-Rwn').style.display = 'none'; // 添加左下角加载提示 let loadingElement = document.createElement('div'); loadingElement.style = "width: 5em; height: 5em; position: fixed; background-color: #4c97ff; right: 5%; opacity: 0.8; bottom: 5%; border-radius: 8px;"; loadingElement.id = "explore-loading"; loadingElement.innerHTML = '
'; document.body.appendChild(loadingElement) // 把 onLoading 设为 true onLoading = true; // 然而隐藏了蓝色加载提示,作品加载的时候那个没加载出来的白色舞台就会暴露给用户,于是便要给加载中的作品来一个遮盖。 // 如果 onProjectLoading 还没被设为 true,而且是作品在加载(全屏加载遮盖带有类似“加载拓展”等的提示消息)、作品区已经被创建(检测页面上是否有作品区控制区域,就是绿旗、红六边形那个区域) } else if ( onLoading == true && onProjectLoading == false && elementExist('.loader_message-container-outer_oYjTv') && elementExist('.stage-header_stage-header-wrapper_8psPs') ) { // 这里检测是否是手机端依靠的是手机端的舞台区域的 class 是 ...-wrapper-mobile_2WJLy,和电脑端不一样 // 使作品区控制区域不可点击(如果是手机端就直接隐藏了) document.querySelector('.stage-header_stage-header-wrapper_8psPs').style = elementExist('.stage-wrapper_stage-canvas-wrapper-mobile_2WJLy') ? 'display: none;' : 'opacity: 0.5; pointer-events: none;'; // 使其不可点击 // 对症下药,如果是手机端就改手机端的 ...-wrapper-mobile_2WJLy,如果是电脑端就改电脑端的 ...-wrapper_n2Q5r,给它用 Display: none 隐藏掉 document.querySelector( elementExist('.stage-wrapper_stage-canvas-wrapper-mobile_2WJLy') ? '.stage-wrapper_stage-canvas-wrapper-mobile_2WJLy' : '.stage-wrapper_stage-canvas-wrapper_n2Q5r').style = 'display: none'; // 隐藏 // 在作品区添加加载中的蓝色方框(这里其实是把原来的舞台隐藏掉,拿这个东西放上去,看起来像是给原来的舞台加了遮盖,但其实并不是遮盖) let projectLoadingDOM = document.createElement('div'); projectLoadingDOM.style = "position: relative; border-radius: 8px; padding: 8px; display: block !important; z-index: 1 !important;"; projectLoadingDOM.id = "explore-loading-project"; projectLoadingDOM.classList.add("loader_background_1-Rwn"); projectLoadingDOM.innerHTML = '
载入项目
正在创建积木……
载入角色……
载入声音……
加载扩展……
正在创建积木……
呼唤小猫……
传送Nano……
给Gobo充气 …
准备表情……
'; document.querySelector('.stage-wrapper_stage-wrapper_3k56F').appendChild(projectLoadingDOM); // 把 onProjectLoading 设为 true onProjectLoading = true; } // 如果全屏加载遮盖已经消失了,但是 onLoading 还是 true,说明还没给原来的左下角/作品加载提示移除掉 } else if ( onLoading == true ){ // 移除左下角加载提示 document.querySelector('#explore-loading').remove(); if( onProjectLoading == true ) { // 把原来禁止点击的、隐藏的恢复原状 document.querySelector('.stage-header_stage-header-wrapper_8psPs').style = ''; document.querySelector( elementExist('.stage-wrapper_stage-canvas-wrapper-mobile_2WJLy') ? '.stage-wrapper_stage-canvas-wrapper-mobile_2WJLy' : '.stage-wrapper_stage-canvas-wrapper_n2Q5r').style = ''; // 移除加载的蓝色方框 document.querySelector('#explore-loading-project').remove(); onProjectLoading = false; } // 把 onLoading 设为 false onLoading = false; } },100) } } // // 添加不文明用语警告的“不再提示” window.disableBadWordsWarning = false; setInterval(()=>{ if( document.querySelector('.body.box_box_tWy-0') == null ) return; if ( document.querySelector('.body.box_box_tWy-0').innerHTML.includes('正在提交的内容中包含疑似不文明用语') ) { // 禁用了不文明用语警告,那就直接点“确定” if(window.disableBadWordsWarning) { document.querySelector('.ok-button').click(); // 如果未禁用不文明用语警告,并且也还没有添加“不再提示”的 checkbox,那就添加上 } else if ( !document.querySelector('.body.box_box_tWy-0').childNodes[0].innerHTML.includes('checkbox') ){ document.querySelector('.body.box_box_tWy-0').childNodes[0].innerHTML += '
谢了,我知道该怎么做'; } } },200); })();