// ==UserScript==
// @name 洛谷犇犇 Better
// @namespace http://tampermonkey.net/
// @version 4.1
// @description 增加洛谷犇犇回复 Markdown,防止错误 @,优化删除行为,增加 Sweetalert(请先开启学术模式,不影响正常使用)
// @author nr0728 & _s_z_y_
// @match https://www.luogu.com.cn/*
// @license MIT
// @grant none
// @require https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js
// ==/UserScript==
(function() {
'use strict';
if (window.location.href === 'https://www.luogu.com.cn/') {
let targetDiv = document.querySelector('.am-u-lg-9.am-u-md-8.lg-index-benben.lg-right');
if (targetDiv) {
let newDiv = document.createElement('div');
newDiv.className = 'lg-article';
newDiv.innerHTML = `
<h2>有什么新鲜事告诉大家</h2>
<div class="am-form-group am-form">
<textarea rows="3" id="feed-content"></textarea>
</div>
<button class="am-btn am-btn-danger am-btn-sm" id="feed-submit"> 发射犇犇! </button>
`;
targetDiv.appendChild(newDiv);
let navDiv = document.createElement('div');
navDiv.className = 'lg-article';
navDiv.innerHTML = `
<ul class="am-nav am-nav-pills am-nav-justify" id="home-center-nav">
<li class="feed-selector am-active" data-mode="watching"><a style="cursor: pointer">我关注的</a></li>
<li class="feed-selector" data-mode="my"><a style="cursor: pointer">我发布的</a></li>
</ul>
`;
targetDiv.appendChild(navDiv);
let feedList = document.createElement('ul');
feedList.className = 'am-comments-list am-comments-list-flip';
feedList.id = 'feed';
targetDiv.appendChild(feedList);
document.getElementById('feed-submit').addEventListener('click', function() {
let content = document.getElementById('feed-content').value;
$.ajax({
type: "POST",
url: 'https://www.luogu.com.cn/api/feed/postBenben',
data: {
content: content
},
success: function(response) {
Sweetalert2.fire({
icon: 'success',
title: '发送成功',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500,
timerProgressBar: true
});
document.getElementById('feed-content').value = '';
},
error: function(error) {
Sweetalert2.fire({
icon: 'error',
title: '发送失败,请稍后再试!',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500,
timerProgressBar: true
});
}
});
});
let currentPage = 1;
let stopLoadingMore = false;
document.querySelectorAll('.feed-selector').forEach(function(elem) {
elem.addEventListener('click', function() {
let mode = this.getAttribute('data-mode');
currentPage = 1;
stopLoadingMore = false;
let url = mode === 'watching'
? `https://www.luogu.com.cn/feed/watching?page=${currentPage}`
: `https://www.luogu.com.cn/feed/my?page=${currentPage}`;
document.querySelectorAll('.feed-selector').forEach(function(item) {
item.classList.remove('am-active');
});
this.classList.add('am-active');
loadFeedContent(url, true);
});
});
document.querySelector('.feed-selector[data-mode="watching"]').click();
function loadFeedContent(url, isNewLoad) {
fetch(url)
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let content = doc.querySelector('body').innerHTML;
if (isNewLoad) {
feedList.innerHTML = content;
} else {
feedList.innerHTML += content;
}
if (content.includes('<h2>没有更多动态了</h2>')) {
stopLoadingMore = true;
}
let oldMore = document.getElementById('feed-more');
if (oldMore) {
oldMore.remove();
}
if (!stopLoadingMore) {
addLoadMoreButton(url);
}
bindFeedButtons();
})
.catch(error => console.error('Error loading feed:', error));
}
function bindFeedButtons() {
document.querySelectorAll('a[name="feed-delete"]').forEach(function(deleteButton) {
deleteButton.addEventListener('click', function() {
let feedId = this.getAttribute('data-feed-id');
$.post(`/api/feed/delete/${feedId}`, function(response) {
Sweetalert2.fire({
icon: 'success',
title: '删除成功',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500,
timerProgressBar: true
});
deleteButton.closest('.am-comment').remove();
}).fail(function() {
Sweetalert2.fire({
icon: 'error',
title: '删除失败,请稍后再试!',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500,
timerProgressBar: true
});
});
});
});
document.querySelectorAll('a[name="feed-reply"]').forEach(function(replyButton) {
replyButton.addEventListener('click', function() {
let commentElement = this.closest('.am-comment').querySelector('.feed-comment');
let headerElement = this.closest('.am-comment').querySelector('.am-comment-meta .feed-username a');
let username = headerElement ? headerElement.textContent.trim() : 'unknown';
let rawHTML = commentElement.innerHTML;
let markdown = convertHtmlToMarkdown(rawHTML);
let textarea = document.getElementById('feed-content');
textarea.value = ` || @${username} : ${markdown}`;
});
});
}
function addLoadMoreButton(baseUrl) {
let moreDiv = document.createElement('div');
moreDiv.className = 'lg-article am-text-center';
moreDiv.id = 'feed-more';
moreDiv.innerHTML = `<a>点击查看更多...</a>`;
targetDiv.appendChild(moreDiv);
moreDiv.addEventListener('click', function() {
currentPage++;
let nextUrl = baseUrl.replace(/page=\d+/, `page=${currentPage}`);
loadFeedContent(nextUrl, false);
});
}
function convertHtmlToMarkdown(html) {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let traverseNode = function(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent;
} else if (node.nodeType === Node.ELEMENT_NODE) {
switch (node.tagName.toLowerCase()) {
case 'strong': {
return `__${Array.from(node.childNodes).map(traverseNode).join('')}__`;
}
case 'em': {
return `_${Array.from(node.childNodes).map(traverseNode).join('')}_`;
}
case 'del': {
return `~~${Array.from(node.childNodes).map(traverseNode).join('')}~~`;
}
case 'a': {
let href = node.getAttribute('href');
let text = Array.from(node.childNodes).map(traverseNode).join('');
if (node.previousSibling && node.previousSibling.nodeType === Node.TEXT_NODE && node.previousSibling.textContent.endsWith('@')) {
return text;
}
if (text === href) {
return `<${href}>`;
}
return `[${text}](${href})`;
}
case 'code': {
if (node.parentElement && node.parentElement.tagName.toLowerCase() === 'pre') {
return Array.from(node.childNodes).map(traverseNode).join('');
}
return `\`${Array.from(node.childNodes).map(traverseNode).join('')}\``;
}
case 'pre': {
let codeContent = Array.from(node.childNodes).map(traverseNode).join('');
return `\n\`\`\`\n${codeContent}\n\`\`\``;
}
case 'h1': {
return `\n# ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'h2': {
return `\n## ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'h3': {
return `\n### ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'h4': {
return `\n#### ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'h5': {
return `\n##### ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'h6': {
return `\n###### ${Array.from(node.childNodes).map(traverseNode).join('')}\n`;
}
case 'hr': {
return `---`;
}
case 'ul': {
return `${Array.from(node.childNodes).map(traverseNode).join('').trim()}`;
}
case 'ol': {
return `${Array.from(node.childNodes).map(traverseNode).join('').trim()}`;
}
case 'li': {
if (node.parentElement.tagName.toLowerCase() === 'ol') {
let index = Array.from(node.parentElement.children).indexOf(node) + 1;
return `${index}. ${Array.from(node.childNodes).map(traverseNode).join('').trim()}`;
} else {
return `- ${Array.from(node.childNodes).map(traverseNode).join('').trim()}`;
}
}
case 'quote': {
let quoteContent = Array.from(node.childNodes).map(traverseNode).join('').trim();
return `\n> ${quoteContent.trim().replace(/\n/g, '\n> ')}\n`;
}
case 'blockquote': {
let blockquoteContent = Array.from(node.childNodes).map(traverseNode).join('').trim();
return `\n> ${blockquoteContent.trim().replace(/\n/g, '\n> ')}\n`;
}
case 'p': {
return `${Array.from(node.childNodes).map(traverseNode).join('').trim()}\n`;
}
case 'br': {
return `\n`;
}
case 'img': {
let src = node.getAttribute('src');
let alt = node.getAttribute('alt') || '';
return ``;
}
default: {
return Array.from(node.childNodes).map(traverseNode).join('');
}
}
}
return '';
};
return '\n' + Array.from(doc.body.childNodes).map(traverseNode).join('') + '\n';
}
}
}
if (1) {
const urlParams = new URLSearchParams(window.location.search);
const forum = urlParams.get('forum');
setInterval(function() {
const urlParams = new URLSearchParams(window.location.search);
let sectionDiv = document.querySelector('div.section');
const forum = urlParams.get('forum');
let targetElement = sectionDiv.querySelector('div.row-item');
if (sectionDiv && forum !== 'relevantaffairs') {
let existingLink = sectionDiv.querySelector('a[href="/discuss?forum=relevantaffairs"]');
if (!existingLink) {
let newLink = document.createElement('a');
newLink.href = '/discuss?forum=relevantaffairs';
newLink.className = 'forum-container section-item row-item router-link-exact-active router-link-active color-default link';
newLink.title = '灌水区';
newLink.style = '--forum-color: #52c41a; color: var(--forum-color);';
newLink.innerHTML = `
<svg data-v-d6def288 aria-hidden="true" focusable="false" data-prefix="fas" data-icon="square" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="forum-icon svg-inline--fa fa-square">
<path fill="currentColor" d="M0 96C0 60.7 28.7 32 64 32H384c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96z"></path>
</svg>
<span data-v-d6def288 class="forum-name">灌水区</span>
`;
sectionDiv.insertBefore(newLink, targetElement);
}
}
}, 100);
}
})();