// ==UserScript== // @name U2实时预览BBCODE // @namespace https://u2.dmhy.org/ // @version 0.1.1 // @description 实时预览BBCODE // @author kysdm // @grant none // @match *://u2.dmhy.org/upload.php* // @match *://u2.dmhy.org/edit.php* // @match *://u2.dmhy.org/forums.php?action=* // @match *://u2.dmhy.org/comment.php?action=* // @icon https://u2.dmhy.org/favicon.ico // @downloadURL none // ==/UserScript== /* 更新日志 https://github.com/kysdm/u2_share/commits/main/u2share_bbcode.user.js */ /* 无法显示的 Tag 由U2自带上传工具上传的文件 Flash 有关的 Tag 从弹窗添加表情 [https://u2.dmhy.org/moresmilies.php?form=upload&text=descr] <不知道能不能修> 我不知道的特殊操作 */ /* 待实现的功能 多语言支持 显示标题 使用原生JS实现 <本来是原生JS的,写着写着觉得好繁琐,就上jq了。> */ /* 与U2娘显示不同的标签 (非标准操作) [spoiler="剧透是不"可能的!"]真的![/spoiler] U2 => "剧透是不"可能的!" Script => 剧透是不"可能的! */ (async () => { 'use strict'; new init(); let currentTab = 0; $('.bbcode').parents("tr:eq(1)").after('' + '预览
' + '
' + '
' + bbcode2html($('.bbcode').val()) + '
'); // https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; let element = document.querySelector('.bbcode'); var height_now, height_last; var observer = new MutationObserver((mutations) => { mutations.forEach(function (mutation) { if (mutation.type == "attributes") { height_now = Number(mutation.target.style.height.replace('px', '')) + 30; if (height_last === height_now) { return } else { height_last = height_now; }; $("#bbcode2").css("max-height", height_now + "px"); } }) }); observer.observe(element, { attributes: true, attributeFilter: ['style'] }); $('.bbcode').scroll(() => { if (currentTab !== 1) return; let scale = ($('#bbcode2').children('.child').get(0).offsetHeight - $('#bbcode2').get(0).offsetHeight) / ($('.bbcode').get(0).scrollHeight - $('.bbcode').get(0).offsetHeight); $('#bbcode2').scrollTop($('.bbcode').scrollTop() * scale); }); $('#bbcode2').scroll(() => { if (currentTab !== 2) return; let scale = ($('#bbcode2').children('.child').get(0).offsetHeight - $('#bbcode2').get(0).offsetHeight) / ($('.bbcode').get(0).scrollHeight - $('.bbcode').get(0).offsetHeight); $('.bbcode').scrollTop($('#bbcode2').scrollTop() / scale); }); $('.bbcode').mouseover(() => { currentTab = 1; }); $('#bbcode2').mouseover(() => { currentTab = 2; }); $('.bbcode').bind('input propertychange', async function updateValue() { let html = bbcode2html($(this).val()); $('#bbcode2').children('.child').html(html); }); $('.codebuttons').click(async function updateValue() { let html = bbcode2html($('.bbcode').val()); $('#bbcode2').children('.child').html(html); }); $("td.embedded.smile-icon a").click(async function updateValue() { await sleep(0); let html = bbcode2html($('.bbcode').val()); $('#bbcode2').children('.child').html(html); }); })(); async function sleep(interval) { return new Promise(resolve => { setTimeout(resolve, interval); }) } function bbcode2html(bbcodestr) { const f_reg = new RegExp("^\"?\"?$"); var tempCode = new Array(); var tempCodeCount = 0; function addTempCode(value) { tempCode[tempCodeCount] = value; let returnstr = ""; tempCodeCount++; return returnstr; } const escape_reg = new RegExp("[&\"\'<>]", "g"); bbcodestr = bbcodestr.replace(escape_reg, function (s, x) { switch (s) { case '&': return '&'; case '"': return '"'; case "'": return '''; case '<': return '<'; case '>': return '>'; default: return s; } }); bbcodestr = bbcodestr.replace(/\r\n/g, () => { return '
' }); bbcodestr = bbcodestr.replace(/\n/g, () => { return '
' }); bbcodestr = bbcodestr.replace(/\r/g, () => { return '
' }); // code 标签 const code_reg = new RegExp("\\[code\\](.+?)\\[\\/code\\]", "gis"); bbcodestr = bbcodestr.replace(code_reg, function (s, x) { return addTempCode('
代码
' + x + '

'); }); // info 标签 const info_reg = new RegExp("\\[(mediainfo|info)\\](.+?)\\[\\/(\\1)\\]", "gis"); bbcodestr = bbcodestr.replace(info_reg, function (s, x, y) { switch (x) { case 'info': return addTempCode('
发布信息' + '' + y + '
'); case 'mediainfo': return addTempCode('
媒体信息' + '' + y + '
'); default: return s; } }); // 单个标签 不带参 const o_reg = new RegExp("\\[(\\*|siteurl|site)\\]", "gi"); bbcodestr = bbcodestr.replace(o_reg, function (s, x, y) { switch (x) { case '*': return 'list'; case 'site': return 'U2分享園@動漫花園'; case 'siteurl': return 'https://u2.dmhy.org'; default: return s; } }); // 成对标签 带参 const d_reg = new RegExp("\\[(rt|font)=([^\\]]+)\\](.*?)\\[(/\\1)\\]", "gis"); while (d_reg.test(bbcodestr)) { bbcodestr = bbcodestr.replace(d_reg, function (s, w, x, y, z) { switch (w) { case 'rt': if (f_reg.test(x)) { return '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + w) + '=' + x + ']' + y + '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + z) + ']' } else { return '' + y + '(' + x.replace(/^"?(.*?)"?$/, "$1") + ')'; } case 'font': if (f_reg.test(x)) { return '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + w) + '=' + x + ']' + y + '[' + addTempCode('p3F#oW2@cEn_JHstp-&37DgD' + z) + ']'; } else { return '' + y + ''; } default: return s; } }) }; // 成对标签 不带参 const a_reg = new RegExp("\\[(pre|b|i|u|s)\\](.*?)\\[/(\\1)\\]", "gs"); while (a_reg.test(bbcodestr)) { bbcodestr = bbcodestr.replace(a_reg, function (s, x, y, z) { switch (x) { case 'b': return '' + y + ''; case 'i': return '' + y + ''; case 'u': return '' + y + ''; case 's': return '' + y + ''; case 'pre': return '
' + y + '
'; default: return s; } }) }; // 颜色 const color_reg = new RegExp("\\[color=\"?([#0-9a-z]{1,15}|[a-z]+?)\"?\\](.*?)\\[/color\\]", "gis"); while (color_reg.test(bbcodestr)) { bbcodestr = bbcodestr.replace(color_reg, function (s, x, y) { return '' + y + ''; }) }; // 文字大小 const size_reg = new RegExp("\\[size=\"?([1-7])\"?\\](.*?)\\[/size\\]", "gis"); while (size_reg.test(bbcodestr)) { bbcodestr = bbcodestr.replace(size_reg, function (s, x, y) { return '' + y + ''; }) }; // 图片 bbcodestr = bbcodestr.replace(/\[(img|imglnk)\]([^\]]+)\[\/(?:\1)\]/gi, function (s, x, y) { if (/^https?:\/\/((?!<|>|\s|"|>|'|<|;|\(|\)|\[|\]).)+$/i.test(y)) { switch (x) { case 'img': return addTempCode('image'); case 'imglnk': return addTempCode('image'); } } else { return addTempCode(s) } }); bbcodestr = bbcodestr.replace(/\[img=([^\]]+)\]/gi, function (s, x) { if (/^https?:\/\/((?!<|>|\s|"|>|'|<|;|\(|\)|\[|\]).)+$/i.test(x)) { return addTempCode('image'); } else { return addTempCode(s) } }); // 超链接 bbcodestr = bbcodestr.replace(/\[url=((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!<|>|\s|"|>|'|<|\(|\)|\[|\]).)+)\](.+?)\[\/url\]/gis, function (s, x, y, z) { return addTempCode('' + z + ''); }); bbcodestr = bbcodestr.replace(/\[url\]((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!<|>|\s|"|>|'|<|\(|\)|\[|\]).)+)\[\/url\]/gis, function (s, x) { return addTempCode('' + x + '') }); bbcodestr = bbcodestr.replace(/((?:https?|ftp|gopher|news|telnet|mms|rtsp):\/\/((?!<|>|\s|"|>|'|<|\(|\)|\[|\]).)+)/gi, function (s, x) { return '' + s + ''; }); // 引用 const quote_reg1 = new RegExp("\\[quote\\](.*?)\\[/quote\\]", "gsi"); while (quote_reg1.test(bbcodestr)) { bbcodestr = bbcodestr.replace(quote_reg1, function (s, x) { return '
引用' + x + '
'; }); }; const quote_reg2 = new RegExp("\\[quote=([^\\]]*)\\](.*?)\\[/quote\\]", "gsi"); while (quote_reg2.test(bbcodestr)) { bbcodestr = bbcodestr.replace(quote_reg2, function (s, x, y) { if (f_reg.test(x)) { return '
引用' + y + '
'; } else { return '
引用: ' + x.replace(/^"(.*?)"?$/, "$1") + '' + y + '
'; } }); }; // spoiler const spoiler_reg1 = new RegExp("\\[spoiler\\](.*?)\\[/spoiler\\]", "gsi"); const spoiler_reg2 = new RegExp("\\[spoiler=([^\\]]+)\\](.*?)\\[/spoiler\\]", "gsi"); while (spoiler_reg1.test(bbcodestr)) { bbcodestr = bbcodestr.replace(spoiler_reg1, function (s, x) { return '
' + '警告!下列文字很可能泄露剧情,请谨慎选择是否观看。  ' + '' + '' + '
' + x + '
'; }); }; while (spoiler_reg2.test(bbcodestr)) { bbcodestr = bbcodestr.replace(spoiler_reg2, function (s, x, y) { if (f_reg.test(x)) { return '
' + '警告!下列文字很可能泄露剧情,请谨慎选择是否观看。  ' + '' + '' + '
' + y + '
'; } else { return '
' + x.replace(/^"(.*?)"?$/, "$1") + '  ' + '' + '' + '
' + y + '
'; } }); }; // 表情 const em_reg = new RegExp("\\[(em[1-9][0-9]*)\\]", "gi"); bbcodestr = bbcodestr.replace(em_reg, function (s, x) { switch (x) { case (x.match(/^em[1-9][0-9]*/i) || {}).input: return '[' + x + ']'; default: return s; } }) for (let i = 0, len = tempCode.length; i < len; i++) { // console.log(i + " : " + tempCode[i]); bbcodestr = bbcodestr.replace("", tempCode[i]); } bbcodestr = bbcodestr.replace(/p3F#oW2@cEn_JHstp-&37DgD/g, ""); if (/(
)$/.test(bbcodestr)) { bbcodestr = bbcodestr + '
' } // console.log(bbcodestr); // console.log(tempCode); return bbcodestr; } function init() { var h1 = $('.codebuttons').eq(6).parent().html(); var h2 = $('.codebuttons').eq(7).parent().html(); var h3 = $('.codebuttons').eq(8).parent().html(); $('.codebuttons').eq(8).parent().remove(); $('.codebuttons').eq(7).parent().remove(); $('.codebuttons').eq(6).parent().remove(); $('.codebuttons').eq(2).parent().after(''); $('.codebuttons').eq(5).parent() .after('') .after('') .after('') .after(''); $('.codebuttons').eq(10).attr("onclick", "onEditorActionS('descr','EDITOR_QUOTE')"); $('.codebuttons').eq(10).parent() .after('') .after('') .after('') .after('') .after(''); $('.codebuttons').parents('td:not(.embedded,.rowfollow,.text,.outer)').append('
' + h1 + '' + h2 + '' + h3 + '
'); const margin = $('.codebuttons').parents('tbody').eq(0).width() - $("#select_list").width() - 2.6; $("#select_list").css("margin-left", margin + "px"); $('body').append( '' ); }