U2实时预览BBCODE

实时预览BBCODE

目前為 2021-05-10 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         U2实时预览BBCODE
// @namespace    https://u2.dmhy.org/
// @version      0.0.3
// @description  实时预览BBCODE
// @author       kysdm
// @grant        none
// @match        *://u2.dmhy.org/upload.php*
// @match        *://u2.dmhy.org/edit.php*
// @icon         https://u2.dmhy.org/favicon.ico
// ==/UserScript==

/*
无法显示的 Tag
    由U2自带上传工具上传的文件
    Flash 有关的 Tag <u2好像本来就不支持>
    从弹窗添加表情 [https://u2.dmhy.org/moresmilies.php?form=upload&text=descr] <不知道能不能修>
    我不知道的特殊操作
*/

/*
待实现的功能
    多语言支持
    显示标题
    使用原生JS实现 <本来是原生JS的,写着写着觉得好繁琐,就上jq了。>
*/

/*
不会加入的功能
    预览除了发布和编辑种子页面的BBCODE  https://u2.dmhy.org/upload.php || https://u2.dmhy.org/edit.php*
*/

/*
与U2娘显示不同的标签 (非标准操作)
    [spoiler="剧透是不"可能的!"]真的![/spoiler]
        U2      => "剧透是不"可能的!"
        Script  => 剧透是不"可能的!
    http://u2.dmhy.or'g/upload.php || http://u2.dmhy.or"g/upload.php
        U2      => http://u2.dmhy.or'g/upload.php 视为 url
        Script  => http://u2.dmhy.or 视为url 'g/upload.php 视为 str
*/

/*
[b]这是粗体。[/b]
[i]这是斜体。[/i]
[u]这是下划线。[/u]
[s]这是删除线。[/s]
你真是个[rt=biàn]绅[/rt][rt=tài]士[/rt]。
[color=blue]这是蓝色文字。[/color]
[color=#0000ff]这是蓝色文字。[/color]
[size=4]这是4号字的文字。[/size]
[font=SimHei]世界您好![/font]
[url]http://u2.dmhy.org[/url]
[url=http://u2.dmhy.org]u2.dmhy.org[/url]
[img=http://u2.dmhy.org/pic/logo.png]
[img]http://u2.dmhy.org/pic/logo.png[/img]
[imglnk]http://u2.dmhy.org/pic/logo.png[/imglnk]
[quote]我爱U2分享園@動漫花園。[/quote]
[info]题材............: 动作, 科幻[/info]
[mediainfo]扫描模式 : 逐行[/mediainfo]
[quote="Azusa"]我爱U2分享園@動漫花園。[/quote]
[*]这是项目1
[*]这是项目2
[pre]这是预格式化文字。[/pre]
[code]这是代码文本。[/code]
[spoiler]我要剧透了![/spoiler]
[spoiler="剧透是不可能的!"]真的![/spoiler]
你正在访问[site]。
[site]的网址是[siteurl]。
*/


(async () => {
    'use strict';

    let currentTab = 0;

    $('.bbcode').parents("tr:eq(1)").after('<tr><td class="rowhead nowrap" valign="top" style="padding: 3px" align="right">'
        + '预览</td><td class="rowfollow"><table width="100%" cellspacing="0" cellpadding="5" border="0" ><tbody><tr><td  align="left" colspan="2">'
        + '<div id="bbcode2" style="min-height: 25px; max-height: 350px; overflow-x: auto ; overflow-y: auto;"><div class="child">'
        + bbcode2html($('.bbcode').val()) + '</div></div></td></tr></tbody></table></td>');

    $('.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 br_reg = new RegExp("[\\r\\n]", "g");
    const f_reg = new RegExp("^\"?\"?$");

    var tempCode = new Array();
    var tempCodeCount = 0;

    function addTempCode(value) {
        tempCode[tempCodeCount] = value;
        returnstr = "<tempCode_" + tempCodeCount + ">";
        tempCodeCount++;
        return returnstr;
    }

    // code 标签
    const code_reg = new RegExp("\\[code\\](.+?)\\[\\/code\\]", "gis");
    bbcodestr = bbcodestr.replace(code_reg, function (s, x) {
        return addTempCode('<br /><div class="codetop">代码</div><div class="codemain">' + x + '</div><br />');
    });

    bbcodestr = bbcodestr.replace(br_reg, () => { return '<br />' });

    // 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('<fieldset class="pre"><legend><b><span style="color: blue">发布信息</span>'
                    + '</b></legend>' + y + '</fieldset>');
            case 'mediainfo':
                return addTempCode('<fieldset class="pre"><legend><b><span style="color: red">媒体信息</span>'
                    + '</b></legend>' + y + '</fieldset>');
            default:
                return s;
        }
    });

    // 单个标签 不带参
    const o_reg = new RegExp("\\[(\\*|siteurl|site)\\]", "gi");
    bbcodestr = bbcodestr.replace(o_reg, function (s, x, y) {
        switch (x) {
            case '*':
                return '<img class="listicon listitem" src="pic/trans.gif" alt="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 s;
                    }
                    else {
                        return '<ruby>' + y + '<rp>(</rp><rt>' + x.replace(/^"?(.*?)"?$/, "$1") + '</rt><rp>)</rp></ruby>';
                    }
                case 'font':
                    if (f_reg.test(x)) {
                        return s;
                    }
                    else {
                        return '<span style="font-family: ' + x.replace(/^"?(.*?)"?$/, "$1") + '">' + y + '</span>';
                    }
                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 '<b>' + y + '</b>';
                case 'i':
                    return '<em>' + y + '</em>';
                case 'u':
                    return '<u>' + y + '</u>';
                case 's':
                    return '<s>' + y + '</s>';
                case 'pre':
                    return '<pre>' + y + '</pre>';
                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) {
            if (f_reg.test(x)) {
                return s;
            }
            else {
                return '<span style="color: ' + x.replace(/^"?(.*?)"?$/, "$1") + '">' + y + '</span>';
            }
        })
    }

    // 文字大小
    const size_reg = new RegExp("\\[size=([1-7])\\](.*?)\\[/size\\]", "gis");
    while (size_reg.test(bbcodestr)) {
        bbcodestr = bbcodestr.replace(size_reg, function (s, x, y) {
            if (f_reg.test(x)) {
                return s;
            }
            else {
                return '<font size="' + x.replace(/^"?(.*?)"?$/, "$1") + '">' + y + '</font>';
            }
        })
    }

    // 图片
    const img_reg1 = new RegExp("\\[(img|imglnk)\\](https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])\\[\/(?:\\1)\\]", "gi");
    bbcodestr = bbcodestr.replace(img_reg1, function (s, x, y) {
        switch (x) {
            case 'img':
                return addTempCode('<img alt="image" src="' + y + '" style="height: auto; width: auto; max-width: 100%;">');
            case 'imglnk':
                return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + y + '"><img alt="image" src="'
                    + y + '" style="height: auto; width: auto; max-width: 100%;"></a>');
        }
    });
    const img_reg2 = new RegExp("\\[img=(https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])\\]", "gi");
    bbcodestr = bbcodestr.replace(img_reg2, function (s, x) {
        return addTempCode('<img alt="image" src="' + x + '" style="height: auto; width: auto; max-width: 100%;">');

    });

    // 超链接
    const url_reg1 = new RegExp("\\[url=((?:https?|ftp|gopher|news|telnet|mms|rtsp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])\\](.+?)\\[/url\\]", "gis");
    bbcodestr = bbcodestr.replace(url_reg1, function (s, x, y) {
        return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + y + '</a>');
    });
    const url_reg2 = new RegExp("\\[url\\]((?:https?|ftp|gopher|news|telnet|mms|rtsp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])\\[/url\\]", "gis");
    bbcodestr = bbcodestr.replace(url_reg2, function (s, x) {
        return addTempCode('<a class="faqlink" rel="nofollow noopener noreferer" href="' + x + '">' + x + '</a>')
    });
    const url_reg3 = new RegExp("(?:https?|ftp|gopher|news|telnet|mms|rtsp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]", "gi");
    bbcodestr = bbcodestr.replace(url_reg3, function (s, x) {
        return '<a class="faqlink" rel="nofollow noopener noreferer" href="' + s + '">' + s + '</a>';
    });

    // 引用
    const quote_reg1 = new RegExp("\\[quote\\](.*?)\\[/quote\\]", "gsi");
    bbcodestr = bbcodestr.replace(quote_reg1, function (s, x) {
        return '<fieldset><legend>引用</legend>' + x + '</fieldset>';
    });
    const quote_reg2 = new RegExp("\\[quote=([^\\]]+)\\](.*?)\\[/quote\\]", "gsi");
    bbcodestr = bbcodestr.replace(quote_reg2, function (s, x, y) {
        if (f_reg.test(x)) {
            return '<fieldset><legend>引用</legend>' + y + '</fieldset>';
        }
        else {
            return '<fieldset><legend>引用: ' + x.replace(/^"(.*?)"?$/, "$1") + '</legend>' + y + '</fieldset>';
        }
    });

    // spoiler
    const spoiler_reg1 = new RegExp("\\[spoiler\\](.*?)\\[/spoiler\\]", "gsi");
    const spoiler_reg2 = new RegExp("\\[spoiler=([^\\]]+)\\](.*?)\\[/spoiler\\]", "gsi");
    bbcodestr = bbcodestr.replace(spoiler_reg1, function (s, x) {
        return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
            + '警告!下列文字很可能泄露剧情,请谨慎选择是否观看。&nbsp;&nbsp;<button class="spoiler-button-show">'
            + '我就是手贱</button><button class="spoiler-button-hide" style="display: none;">我真是手贱</button>'
            + '</td></tr><tr><td><span class="spoiler-content">' + x + '</span></td></tr></tbody></table>';
    });
    bbcodestr = bbcodestr.replace(spoiler_reg2, function (s, x, y) {
        if (f_reg.test(x)) {
            return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
                + '警告!下列文字很可能泄露剧情,请谨慎选择是否观看。&nbsp;&nbsp;<button class="spoiler-button-show">'
                + '我就是手贱</button><button class="spoiler-button-hide" style="display: none;">我真是手贱</button>'
                + '</td></tr><tr><td><span class="spoiler-content">' + y + '</span></td></tr></tbody></table>';
        }
        else {
            return '<table class="spoiler" width="100%"><tbody><tr><td class="colhead">'
                + x.replace(/^"(.*?)"?$/, "$1") + '&nbsp;&nbsp;<button class="spoiler-button-show">我就是手贱</button>'
                + '<button class="spoiler-button-hide" style="display: none;">我真是手贱</button>'
                + '</td></tr><tr><td><span class="spoiler-content">' + y + '</span></td></tr></tbody></table>';
        }
    });

    // 表情
    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 '<img src="pic/smilies/' + x.replace("em", "") + '.gif" alt="[' + x + ']">';
            default:
                return s;
        }
    })

    for (let i = 0, len = tempCode.length; i < len; i++) {
        // console.log(i + " : " + tempCode[i]);
        bbcodestr = bbcodestr.replace("<tempCode_" + i + ">", tempCode[i]);
    }

    // console.log(bbcodestr);
    // console.log(tempCode);

    return bbcodestr;
}