打开/关闭菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

用户:UnownHearn/common.js:修订间差异

无编辑摘要
(防卡)
第29行: 第29行:
* 自动转换链接
* 自动转换链接
* @author [[User:UnownHearn]]
* @author [[User:UnownHearn]]
* @version 1.6 (2019/03/23)
* @version 1.7 (2019/03/23)
*/
*/
(function () {
(function () {
var filter = (function (node) {
if (node.nodeType == 3 /* TEXT_NODE */) {
return NodeFilter.FILTER_ACCEPT;
} else if (node.nodeType != 1 /* ELEMENT_NODE */
|| node.tagName.toLowerCase() == "a"
|| node.classList.contains("no-autolink")) {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_SKIP;

})


var rules = [{
var rules = [{
第82行: 第71行:
}];
}];


// generate url link for given text under the rule (E.g. "sm3777" => "https://nicovideo.jp/watch/sm3777")
// generate url link for given `text` with the given `rule` (E.g. "sm3777" => "https://nicovideo.jp/watch/sm3777")
function generateLink(rule, linkableText) {
function generateLink(rule, linkableText) {
if (typeof rule.link === "function") {
if (typeof rule.link === "function") {
第95行: 第84行:
}
}


// create an <a>nchor element with given url link and text
// create an <a>nchor element with given url `link` and `text`
//
function makeAElement(link, text) {
// the returned element only has a text node as its child
var a = document.createElement("a");
function createAnchorElement(link, text) {
a.className = "autolink";
a.href = link;
return $("<a/>").addClass("autolink").attr("href", link).text(text).get(0);

a.textContent = text;
return a;
// var a = document.createElement("a");
// a.className = "autolink";
// a.href = link;
// a.textContent = text;
// return a;
}
}


// try spliting the given text to three parts by rules.
// try detaching a linkable text from given `text` with given `rules`
//
function matchRules(text, rules) {
// If a rule matches, it will return a tuple contains:
// text before the linkable text, <a>nchor element that represents the linkable text (or a text node), text after the linkable text;
// Otherwise, it will return a tuple contains: "", null, and the original text.
function detachLinkableText(text, rules) {
for (var ruleIndex in rules) {
for (var ruleIndex in rules) {
var rule = rules[ruleIndex];
var rule = rules[ruleIndex];
第112行: 第109行:
var textBefore = text.slice(0, match.index);
var textBefore = text.slice(0, match.index);
var linkableText = match[0];
var linkableText = match[0];
var remainText = text.slice(match.index + linkableText.length);
var link = generateLink(rule, linkableText);
var link = generateLink(rule, linkableText);
var aElement = makeAElement(link, linkableText);
if (link == null) {
return [textBefore, document.createTextNode(linkableText), remainText];
var remainText = text.slice(match.index + match[0].length);
return [textBefore, aElement, remainText];
}
return [textBefore, createAnchorElement(link, linkableText), remainText];
}
}
}
}
第124行: 第123行:
var foundTextNodes = [];
var foundTextNodes = [];


{ //< put all text nodes that under `.WikiaArticle` elements but not under `a` or `.no-autolink` elements into `foundTextNodes`
var articles = document.getElementsByClassName("WikiaArticle");
var articles = document.getElementsByClassName("WikiaArticle");
Array.prototype.forEach.call(articles, function (article) {
var walker = document.createTreeWalker(article, NodeFilter.SHOW_ALL, { acceptNode: filter });
var filter = (function (node) {
while (walker.nextNode()) {
if (node.nodeType == 3 /* TEXT_NODE */) {
foundTextNodes.push(walker.currentNode);
return NodeFilter.FILTER_ACCEPT;
}
} else if (node.nodeType != 1 /* ELEMENT_NODE */
|| node.tagName.toLowerCase() == "a"
})
|| node.classList.contains("no-autolink")) {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_SKIP;
})
Array.prototype.forEach.call(articles, function (article) {
var walker = document.createTreeWalker(article, NodeFilter.SHOW_ALL, { acceptNode: filter });
while (walker.nextNode()) {
foundTextNodes.push(walker.currentNode);
}
})
}

for (var nodeIndex in foundTextNodes) {
for (var nodeIndex in foundTextNodes) {
var foundTextNode = foundTextNodes[nodeIndex];
var foundTextNode = foundTextNodes[nodeIndex];
var remainText = foundTextNode.textContent;
var remainText = foundTextNode.textContent;
var nodes = []; //< will only contain text nodes and <a>nchor element nodes
// this array will only contain text nodes and <a>nchor element nodes that have text nodes
var nodes = [];

while (true) {
while (true) {
var rets = matchRules(remainText, rules);
var _remainText = remainText;

var rets = detachLinkableText(remainText, rules);
var textBefore = rets[0];
var textBefore = rets[0];
var aElement = rets[1];
var elem = rets[1];
remainText = rets[2];
remainText = rets[2];
if (aElement === null) {
if (elem === null) {
// no (more) matches
// no rule matches
break;
break;
}
}
第149行: 第163行:
nodes.push(document.createTextNode(textBefore));
nodes.push(document.createTextNode(textBefore));
}
}
nodes.push(aElement);
nodes.push(elem);

if (_remainText === remainText) {
throw "Infinite Loop!"
}
}
}

if (nodes.length !== 0) { // needs to replace
if (nodes.length !== 0) { //< check if need to replace the original node
nodes.push(document.createTextNode(remainText));
nodes.push(document.createTextNode(remainText));
$(foundTextNode).replaceWith(nodes);
$(foundTextNode).replaceWith(nodes);

2019年3月23日 (六) 17:33的版本

"use strict";

/**
 * 在鼠标移至文本与标题不同的 wikilink 上时, 弹出带有原标题的 popup
 * @author [[User:UnownHearn]]
 * @version 1 (2018/07/28)
*/
(function () {
    // https://stackoverflow.com/questions/14346414/how-do-you-do-html-encode-using-javascript
    function htmlEncode(value) {
        //create a in-memory div, set it's inner text(which jQuery automatically encodes)
        //then grab the encoded contents back out.  The div never exists on the page.
        return $('<div/>').text(value).html();
    }

    $(".WikiaArticle a[title]").hover(function () {
        if (this.className != "") { return; } // 作为 wikilink 的超链接没有 class
        var a = $(this);
        var title = a.attr("title");
        if (title != a.text()) {
            a.append($('<span class="wikilink-popup">' + htmlEncode(title) + '</span>'));
        }
    }, function () {
        $(this).find(".wikilink-popup").remove();
    });
})();

/**
* 自动转换链接
* @author [[User:UnownHearn]]
* @version 1.7 (2019/03/23)
*/
(function () {

    var rules = [{
        // 两字母 + 一串数字
        regex: /[a-zA-Z]{2}\d+/,
        link: function (text) {
            var base;
            switch (text.slice(0, 2)) {
                // niconico 主要
                case "sm": case "nm": base = "https://www.nicovideo.jp/watch/"; break;
                case "im": base = "https://seiga.nicovideo.jp/seiga/"; break;
                // bilibili
                case "av": base = "https://www.bilibili.com/video/"; break;
                case "cv": /*专栏*/ base = "https://www.bilibili.com/read/"; break;
                case "am": /*音频*/ base = "https://www.bilibili.com/audio/"; break;
                // acfun
                case "ac": base = "http://www.acfun.cn/v/"; break;
                // niconico 其他, 参考: https://dic.nicovideo.jp/a/nico.ms
                case "sg": case "mg": case "bk": /*静画*/ base = "https://seiga.nicovideo.jp/watch/"; break;
                case "lv": /*生放送*/ base = "https://live.nicovideo.jp/watch/"; break;
                /* l/co 略去 */
                case "co": /*社区*/ base = "https://com.nicovideo.jp/community/"; break;
                case "ch": /*频道*/ base = "https://ch.nicovideo.jp/channel/"; break;
                case "ar": /*频道文章*/ base = "https://ch.nicovideo.jp/article/"; break;
                case "nd": /*直贩*/ base = "https://chokuhan.nicovideo.jp/products/detail/"; break;
                /* 市场略去 */
                case "ap": /*应用*/ base = "https://app.nicovideo.jp/app/"; break;
                case "jk": /*实况*/ base = "https://jk.nicovideo.jp/watch/"; break;
                case "nc": /*共有*/ base = "https://www.niconicommons.jp/material/"; break;
                case "nw": /*新闻*/ base = "https://news.nicovideo.jp/watch/"; break;
            }
            if (base !== undefined) { return base + text; }
            return null;
        }
    }, {
        // niconico mylist/ 及 user/
        regex: /(mylist|user)\/\d+/,
        link: "https://www.nicovideo.jp/{}"
    }];

    // generate url link for given `text` with the given `rule` (E.g. "sm3777" => "https://nicovideo.jp/watch/sm3777")
    function generateLink(rule, linkableText) {
        if (typeof rule.link === "function") {
            var link = rule.link(linkableText);
            if (link !== null && typeof link !== "string") {
                throw "The return value of link() must be either a string or null!";
            }
            return link;
        } else {
            return rule.link.replace("{}", linkableText);
        }
    }

    // create an <a>nchor element with given url `link` and `text`
    //
    // the returned element only has a text node as its child
    function createAnchorElement(link, text) {
        return $("<a/>").addClass("autolink").attr("href", link).text(text).get(0);

        // var a = document.createElement("a");
        // a.className = "autolink";
        // a.href = link;
        // a.textContent = text;
        // return a;
    }

    // try detaching a linkable text from given `text` with given `rules`
    //
    // If a rule matches, it will return a tuple contains: 
    //      text before the linkable text, <a>nchor element that represents the linkable text (or a text node), text after the linkable text;
    // Otherwise, it will return a tuple contains: "", null, and the original text.
    function detachLinkableText(text, rules) {
        for (var ruleIndex in rules) {
            var rule = rules[ruleIndex];
            var match = rule.regex.exec(text);
            if (match != null) {
                var textBefore = text.slice(0, match.index);
                var linkableText = match[0];
                var remainText = text.slice(match.index + linkableText.length);
                var link = generateLink(rule, linkableText);
                if (link == null) {
                    return [textBefore, document.createTextNode(linkableText), remainText];
                }
                return [textBefore, createAnchorElement(link, linkableText), remainText];
            }
        }
        return ["", null, text];
    }

    function main() {
        var foundTextNodes = [];

        { //< put all text nodes that under `.WikiaArticle` elements but not under `a` or `.no-autolink` elements into `foundTextNodes`
            var articles = document.getElementsByClassName("WikiaArticle");
            var filter = (function (node) {
                if (node.nodeType == 3 /* TEXT_NODE */) {
                    return NodeFilter.FILTER_ACCEPT;
                } else if (node.nodeType != 1 /* ELEMENT_NODE */
                    || node.tagName.toLowerCase() == "a"
                    || node.classList.contains("no-autolink")) {
                    return NodeFilter.FILTER_REJECT;
                }
                return NodeFilter.FILTER_SKIP;
            })
            Array.prototype.forEach.call(articles, function (article) {
                var walker = document.createTreeWalker(article, NodeFilter.SHOW_ALL, { acceptNode: filter });
                while (walker.nextNode()) {
                    foundTextNodes.push(walker.currentNode);
                }
            })
        }

        for (var nodeIndex in foundTextNodes) {
            var foundTextNode = foundTextNodes[nodeIndex];
            var remainText = foundTextNode.textContent;
            // this array will only contain text nodes and <a>nchor element nodes that have text nodes
            var nodes = [];

            while (true) {
                var _remainText = remainText;

                var rets = detachLinkableText(remainText, rules);
                var textBefore = rets[0];
                var elem = rets[1];
                remainText = rets[2];
                if (elem === null) {
                    // no rule matches
                    break;
                }
                if (textBefore !== "") {
                    nodes.push(document.createTextNode(textBefore));
                }
                nodes.push(elem);

                if (_remainText === remainText) {
                    throw "Infinite Loop!"
                }
            }

            if (nodes.length !== 0) { //< check if need to replace the original node
                nodes.push(document.createTextNode(remainText));
                $(foundTextNode).replaceWith(nodes);
            }
        }
    }

    main();

})();