// ==UserScript==
// @name MCBBS Extender
// @namespace https://i.zapic.cc
// @version release-1.1.0
// @description MCBBS行为拓展/样式修复
// @author Zapic
// @match https://*.mcbbs.net/*
// @run-at document-body
// @downloadURL none
// ==/UserScript==
(() => {
// jQuery检查
if (typeof jQuery == "undefined") {
console.error("This page does NOT contain JQuery,MCBBS Extender will not work.");
return false;
}
// 基本信息初始化
let version = "v1.1.0";
let vercode = 111140;
let updatelist = [
'1.新增 查看警告功能,在每个楼层或者个人主页都会添加查看警告记录按钮.',
'2.重写了代码,插入了关键注释,可能会有严重的Bug,如发现请及时向Zapic反馈'
];
let configableList = [{
"id": "fixCodeBlock",
"default": true,
"type": "check",
"name": "美化代码块样式",
"desc": "修正代码块的一些样式,如滚动条."
}, {
"id": "fixCodeCopy",
"default": true,
"type": "check",
"name": "\"复制代码\"修复",
"desc": "修复复制代码时换行全部消失的问题."
}, {
"id": "fixTableLayout",
"default": true,
"type": "check",
"name": "修复表格样式",
"desc": "使用快捷键Shift+F快速修复当前页面表格样式."
}, {
"id": "queryMessage",
"default": true,
"type": "check",
"name": "后台轮询消息",
"desc": "在后台自动查询是否有新的消息并推送,需保证至少打开一个页面."
}, {
"id": "queryMessageInterval",
"default": 60,
"type": "num",
"name": "后台轮询消息间隔",
"desc": "两次轮询消息之间的间隔,单位秒."
}, {
"id": "rememberPage",
"default": true,
"type": "check",
"name": "板块内翻页记忆",
"desc": "点击板块内下一页按钮时记忆当前页."
}, {
"id": "animateGoToTopButton",
"default": true,
"name": "回到顶部按钮美化",
"type": "check",
"desc": "为右侧回到顶部按钮增加动画以及位置修正."
}, {
"id": "pinnedTopBar",
"default": true,
"name": "固定顶栏",
"type": "check",
"desc": "将顶栏固定到页面顶部,不随页面滚动."
}, {
"id": "fixTopBarPopMenu",
"default": true,
"type": "check",
"name": "弹出菜单美化",
"desc": "美化弹出菜单的样式,如个人信息菜单."
}, {
"id": "hoverPreviewTheme",
"default": true,
"name": "主题悬浮预览",
"type": "check",
"desc": "将鼠标指针放在切换主题按钮上即可预览主题."
}, {
"id": "hoverableMedal",
"default": true,
"name": "玻璃质感勋章",
"type": "check",
"desc": "亮闪闪的勋章~"
}, {
"id": "ljyysSearch",
"default": true,
"name": "ljyys搜索",
"type": "check",
"desc": "使用站外搜索代替站内搜索,绕过搜索限制,降低论坛负载,提高搜索效率."
}, {
"id": "quickAtList",
"default": "",
"name": "快速 @ 列表",
"type": "text",
"desc": "按下Ctrl+Shift+A以快速在当前输入框内插入预定义的@用户名代码.用户名之间用\",\"(半角逗号)分隔."
}, {
"id": "viewWarns",
"default": true,
"name": "查看警告记录",
"type": "check",
"desc": "为每一层楼和每一个个人主页(除自己)添加查看警告记录按钮"
}];
//初始化jQuery和基本封装方法
let $ = jQuery;
let dlg = (m) => {
console.debug("[MCBBS Extender]" + m);
};
//配置初始化
let initConfig = () => {
$(configableList).each((i, v) => {
conf[v.id] = typeof conf[v.id] == "undefined" ? v.default : conf[v.id];
});
setcookie("MExt_config", JSON.stringify(conf), 2147483647);
}
let conf = '';
try {
conf = JSON.parse(getcookie("MExt_config"));
} catch (e) {
dlg("Failed to load config\n" + e);
}
if (!conf) {
conf = {};
conf.version = vercode;
initConfig();
showDialog("欢迎使用MCBBS Extender.
本脚本的设置按钮已经放进入了您的个人信息菜单里,如需调整设置请在个人信息菜单里寻找.", "right", "欢迎", () => {
showMenu('user_info');
$("#MExt_config").css("background-color", "#E91E63").css("color", "#fff");
setTimeout(() => {
hideMenu('user_info_menu');
$("#MExt_config").css("background-color", "").css("color", "");
}, 3000);
});
dlg("Config init.");
}
if (typeof conf.version == "undefined" || conf.version < vercode) {
let updateContent = '';
$(updatelist).each((i, v) => {
updateContent += "
" + v;
});
showDialog("MCBBS Extender 已经更新至 " + version + "" + updateContent, "right");
conf.version = vercode;
initConfig();
}
$(() => {
// 设置界面初始化
$("#user_info_menu .user_info_menu_btn").append("
MCBBS Extender 设置");
dlg("Appended Config button");
$("head").append('');
dlg("Appended Config window style");
$("#MExt_config").on("click", () => {
let confwinContent = '';
showDialog(
confwinContent,
"confirm",
"MCBBS Extender 设置",
() => {
$(configableList).each((i, v) => {
let val = '';
if (v.type == "num" || v.type == "text") {
val = $("#in_" + v.id).val();
} else {
val = $("#in_" + v.id).prop("checked");
}
conf[v.id] = val;
});
initConfig();
setTimeout(() => {
showDialog("设置已保存,刷新生效", "right");
});
},
true,
() => {},
"MCBBS Extender " + version + " - 世予可爱w"
);
$(configableList).each((i, v) => {
if (v.type == "num" || v.type == "text") {
$("#in_" + v.id).val(conf[v.id]);
} else {
$("#in_" + v.id).prop("checked", conf[v.id]);
}
});
dlg("Config cookie loaded.");
});
dlg("Config button event attached.");
// 钩住DiscuzAjax函数,使其触发全局事件
let __ajaxpost = ajaxpost;
ajaxpost = (formid, showid, waitid, showidclass, submitbtn, recall) => {
let relfunc = () => {
if (typeof recall == 'function') {
recall();
} else {
eval(recall);
}
$(this).trigger('DiscuzAjaxPostFinished');
}
__ajaxpost(formid, showid, waitid, showidclass, submitbtn, relfunc);
}
let __ajaxget = ajaxget;
ajaxget = (url, showid, waitid, loading, display, recall) => {
let relfunc = () => {
if (typeof recall == 'function') {
recall();
} else {
eval(recall);
}
$(this).trigger('DiscuzAjaxGetFinished');
}
__ajaxget(url, showid, waitid, loading, display, relfunc);
}
dlg("Hooked into Discuz Ajax event");
});
if (conf.fixCodeBlock) {
// 代码块美化样式
$("head").append("");
dlg("Code block fix style appended.");
}
if (conf.fixTableLayout) {
// 监听快捷键事件
$(document).on("keydown", (e) => {
if (e.shiftKey && e.keyCode == 70 && $("#fixTableLayout").length == 0) {
dlg("Table layout fix actived");
showDialog("是否尝试修复此页表格?", "confirm", "MCBBS Extender", () => {
// 添加修复样式
$("head").append("");
})
}
});
dlg("Table layout fix event attached.");
}
if (conf.fixCodeCopy) {
// 重写copycode函数,手动添加换行
copycode = (obj) => {
if (!obj) {
dlg("Code copy with invalid object.");
return false;
}
let code = '';
$(obj).find("li").each((i, v) => {
code += v.innerText + "\r\n";
});
// 复制代码
setCopy(code, '代码已复制到剪贴板');
dlg("Code copied.");
};
dlg("Code copy fix actived.");
}
// 垃圾代码,下个版本重写
if (conf.queryMessage) {
let getRequest = function (variable) {
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i = 0; i < vars.length; i++) {
let pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
return (false);
}
if (location.pathname == "/home.php") {
let action = getRequest('do');
if (action == "pm" || action == "notice") {
$.getJSON("/api/mobile/index.php?module=profile", (data) => {
setcookie("MExt_LastNoticeContent", JSON.stringify(data.Variables.notice), 0);
dlg("Recived msg,flush cache.");
});
}
} else if (new Date().getTime() - localStorage.getItem("notifica-time") > 200000) {
$.getJSON("/api/mobile/index.php?module=profile", (data) => {
setcookie("MExt_LastNoticeContent", JSON.stringify(data.Variables.notice), 0);
dlg("Last notice is 200s or more ago,flush cache.");
});
}
var queryId = hash(new Date().getTime().toLocaleString(), 16);
dlg("Query id is " + queryId + ".");
if (!window.Html5notification) {
$.getScript("data/cache/html5notification.js?xm6");
dlg("Html5notification added.");
}
setInterval(() => {
if (getcookie("MExt_LastQuery") == "") {
setcookie("MExt_LastQuery", 0, 0);
}
var nowtime = Math.floor(new Date().getTime() / 1000);
if ((getcookie("MExt_ActiveQueryId") == "" || nowtime - getcookie("MExt_LastQuery") > 5) && getcookie("MExt_ActiveQueryId") != queryId) {
setcookie("MExt_ActiveQueryId", queryId, 0);
dlg("Kick off inactive querier,start query.");
}
if (getcookie("MExt_ActiveQueryId") == queryId) {
setcookie("MExt_LastQuery", nowtime, 0);
}
}, 1000);
dlg("Running checker actived.");
setInterval(() => {
dlg("Start to check message.");
localStorage.setItem('notifica-time', new Date().getTime());
$.getJSON("/api/mobile/index.php?module=profile", (data) => {
var notices = data.Variables.notice;
var noticecontent = JSON.stringify(notices);
$.get("/forum.php?mod=misc", (d) => {
var dom = $(d);
var ut = dom.find(".user_tools");
var pum = dom.filter("#myprompt_menu");
$(".user_tools").html(ut.html());
$("#myprompt_menu").html(pum.html());
$("title").text(NOTICECURTITLE);
var s = dom.filter("script[src*=html5notification]").nextUntil("div").last().text();
if (getcookie("MExt_ActiveQueryId") == queryId && noticecontent != getcookie("MExt_LastNoticeContent")) {
localStorage.setItem('notifica-time', 1);
eval(s);
dlg("Notification sent.");
}
setcookie("MExt_LastNoticeContent", noticecontent, 0);
});
});
}, conf.queryMessageInterval * 1000);
dlg("Message querier actived.");
}
if (conf.rememberPage) {
// 记住当前页
$(() => {
let npbtn = $("#autobtn");
if(npbtn.length){
let orgfunc = npbtn[0].onclick;
npbtn.on("click",()=>{
let nextpageurl = npbtn.prop('rel');
let curpage = parseInt(npbtn.prop('curpage'));
npbtn.prop('curpage', curpage + 1);
nextpageurl = nextpageurl.replace(/&page=\d+/, '&page=' + (curpage + 1));
history.replaceState(null, null, nextpageurl);
orgfunc();
});
}
dlg("Page remember actived.");
});
}
if (conf.animateGoToTopButton) {
// 添加侧边按钮样式
$("head").append("");
dlg("Animate go to top buttom style appended.");
// 重写showTopLink函数,使其使用侧边栏样式
showTopLink = () => {
let ft = $('#ft')[0];
if (ft) {
let scrolltop = $('#scrolltop')[0];
if (!scrolltop) {
return false;
}
let scrolltopbtn = $(".scrolltopa");
let scrollHeight = parseInt(document.body.getBoundingClientRect().top);
let basew = parseInt(ft.clientWidth);
let sw = scrolltop.clientWidth;
if (basew < 1000) {
let left = parseInt(fetchOffset(ft)['left']);
left = left < sw ? left * 2 - sw : left;
scrolltop.style.left = (basew + left + 44) + 'px';
} else {
scrolltop.style.left = 'auto';
scrolltop.style.right = 0;
}
if (scrollHeight < -100) {
scrolltopbtn.addClass("scrolltopashow");
} else {
scrolltopbtn.removeClass("scrolltopashow");
}
}
}
showTopLink();
dlg("Animate go to top buttom actived.");
}
if (conf.pinnedTopBar) {
// 添加固定顶栏样式
$("head").append("");
$(() => {
// 重写editorcontrolpos函数,与固定顶栏兼容
editorcontrolpos = () => {
if (editorisfull) {
return;
}
var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
if (scrollTop + 47 > editorcontroltop && editorcurrentheight > editorminheight) {
$("#" + editorid + '_controls').prop("style", "z-index:0!important").css("position", 'fixed').css("top", '47px').css("width", editorcontrolwidth + 'px');
$("#" + editorid + '_controls_mask').css("display", '');
} else {
$("#" + editorid + '_controls').css("position", '').css('top', '').css('width', '');
$("#" + editorid + '_controls_mask').css('display', 'none');
}
}
});
dlg("Pinned top bar style appended.");
}
if (conf.fixTopBarPopMenu) {
// 添加弹出菜单美化样式
$("head").append("");
dlg("Pop menu fix style appended.");
// 重写extstyle函数,使更换主题时同步更新样式
let __extstyle = extstyle;
let checkStyle = () => {
let theme = getcookie('extstyle');
if (theme == "./template/mcbbs/style/winter") {
if (!$("#fixTopBarPopMenuWinter").length) {
$("head").append("");
}
} else {
$("#fixTopBarPopMenuWinter").remove();
}
}
extstyle = (style) => {
__extstyle(style);
checkStyle();
}
checkStyle();
dlg("Overwrite extstyle function");
}
if (conf.hoverPreviewTheme) {
//悬浮预览主题
$(() => {
$(".sslct_btn").on("mouseenter", function () {
let that = this;
let timer = setTimeout(function () {
clearTimeout(timer);
var previewstyle = getcookie('extstyle');
$(that).trigger('click');
setcookie('extstyle', previewstyle);
}, 300);
});
$(".sslct_btn").on("mouseleave", () => {
extstyle(getcookie('extstyle'));
});
dlg("Hover preview theme event attached.");
});
}
if (conf.hoverableMedal) {
// 重写勋章结构函数
let rewriteMedal = () => {
// 遍历所有未重写楼层
$('.md_ctrl:not([glassmedal])').attr("glassmedal", "true").each((t, v) => {
// 遍历楼层所有勋章
$(v).children(0).children('img').each((b, n) => {
// 获得勋章ID
let id = 'md' + /\_\d*$/.exec($(n).attr('id'))[0];
// 重写勋章结构
$(v).append(
$('').on('mouseover', () => {
showMenu({
'ctrlid': $(n).attr('id'),
'menuid': id + '_menu',
'pos': '12!'
});
})
);
// 重写提示样式
$("#" + id + "_menu .tip_horn").css("background-image", "url(" + $(n).attr('src') + ")");
// 移除旧的勋章
$(n).remove();
});
});
dlg("Hoverable medal rewrote.");
};
//调用重写勋章函数
$(rewriteMedal);
// 在Ajax时重新调用Ajax函数,保存勋章样式
$(this).on("DiscuzAjaxGetFinished", rewriteMedal).on("DiscuzAjaxPostFinished", rewriteMedal);
// 添加勋章样式
$("head").append("");
dlg("Hoverable medal style appended.");
}
if (conf.ljyysSearch) {
// ljyys serach
$(() => {
$("#scbar_form [type*=hidden]").remove();
$("#scbar_txt").attr("name", "search").css("background-color", "#00000000");
$(".scbar_type_td").html("ljyys搜索").css("background", "url(https://www.mcbbs.net/template/mcbbs/image/scbar_txt.png) -94px center no-repeat").css("width", "62px").css("cursor", "pointer");
$("#scbar_form").attr("method", "get").attr("action", "//search.ljyys.xyz/search.php");
dlg("ljyys search actived");
});
}
if (conf.quickAtList) {
// 获得At代码函数
let getAtCode = () => {
// 分隔list
let quickAtList = conf.quickAtList.split(",");
let atstr = "";
//拼接@代码
$(quickAtList).each((i, v) => {
atstr += "@" + v + " ";
});
return atstr;
}
// 监听按键事件
$(document).on("keydown", (e) => {
if (e.shiftKey && e.ctrlKey && e.keyCode == 65) {
// 判断是否在输入框内
if (($(document.activeElement).prop("nodeName") == "INPUT" && $(document.activeElement).prop("type") == "text")) {
// 拼接方法插入
$(document.activeElement).val($(document.activeElement).val() + getAtCode());
dlg("@ string added");
} else if ($(document.activeElement).prop("nodeName") == "TEXTAREA") {
// discuz内建函数插入
seditor_insertunit('fastpost', '', getAtCode());
dlg("@ string added");
}
}
});
// 高级编辑模式插入@代码
$(() => {
if ($("#e_iframe").length) {
// 由于高级模式的输入框是iFrame,无法直接监听,故再次监听高级输入框的按键事件
$($("#e_iframe")[0].contentWindow).on("keydown", (e) => {
if (e.shiftKey && e.ctrlKey && e.keyCode == 65) {
// 判断是否在输入框内
if ($(document.activeElement).prop("nodeName") == "IFRAME") {
//discuz内建函数插入
insertText(getAtCode());
dlg("@ string added");
}
}
});
}
});
}
if (conf.viewWarns) {
// 添加查看警告样式
$("head").append("");
// 添加查看警告按钮函数
let addVWLink = () => {
$(".plhin").each((i, v) => {
let href = $(v).find(".authi .xw1").attr("href");
if (!href) {
return false;
}
let uid = /uid=(\d*)/.exec(href)[1];
$(v).find("ul.xl.xl2.o.cl:not([vw_added*=true])").attr("vw_added", "true").append($('查看警告记录'));
});
dlg("In-posts view warns link added");
}
// 在DiscuzAjax时重新调用添加函数,防止失效
$(this).on("DiscuzAjaxGetFinished", addVWLink).on("DiscuzAjaxPostFinished", addVWLink);
dlg("adddVWLink Ajax Event attached.");
$(() => {
// 添加查看警告按钮
addVWLink();
// 用户信息界面添加查看警告按钮
let href = $("#uhd .cl a").attr("href");
if (!href) {
return false;
}
let uid = /uid=(\d*)/.exec(href)[1];
if (!uid) {
return false;
}
$("#uhd .mn ul").append('查看警告记录');
dlg("Home page view warns link added.")
});
}
})();